DEV Community

Jules Roadknight
Jules Roadknight

Posted on

Java 'Static' keyword - Intro: How (not) to use it

When do I use the static keyword? What does it do? Doesn't matter, the IDE is telling me where to add it!

With that attitude, my Main class ended up looking like this:

Example 1

public class Main {
    static Contact contact = new Contact();
    static Input input = new Input();

public static void main(String[] args) {
    showMenu();
}

public static void showMenu() {
    int menuChoice;
    menuChoice = input.menuChoice();
    switch (menuChoice) {
        case 1: updateContact();
        default: break;
    }
}

static void updateContact() {
    updateContactFields();
    showContact();
}

static void updateContactFields() {
    // lots of update calls
}

static void showContact() {
    // Lots of prints
    showMenu();
}
}

It was a train-wreck for lots of reasons, but the static everything was causing problems I wasn't aware of.

Bad move Jules

I had priorities, and finding out what all of these (not so) generic keywords meant was low. Anyway, the program worked, and if I made a new method, IntelliJ told me that I couldn't reference a non-static method from a static context, so all of the methods became static.

In the back of my head however, there was something bothering me;

  • The main method in a Java class must be static
  • Every method I was using was directly or indirectly called through the main method
  • Methods called by other classes didn't have to be static, but also could be

So why was I adding this all of the time?

Blocker

Eventually, a combination of using recursion where loops were better and making my entire class static caused problems with state that I couldn't debug. Someone familiar with Java took a quick look and asked me if I knew what static did.

They described it, in Ruby terms, as making something a Class method or variable. I needed instance at most, but had unintentionally made everything global.

Solution/Example 2

public class Main {

    Input input = new Input();
    ArrayList<Contact> contactList = new ArrayList<>();

public static void main(String[] args) {
    Main main = new Main();
    main.showMenu();
}

public void showMenu() {
    boolean complete = false;
    while (!complete) {
        printMenuOptions();
        int userInput = input.menuChoice();
        switch (userInput) {
            case 1: {
                newContact();
                break;
            }
            case 2: {
                updateExistingContact();
                break;
            }
            case 3: {
                showContact();
                break;
            }
            default:
                complete = true;
                break;
        }
    }
}

void printMenuOptions() {
    // logs
}

void newContact() {
    contactList.add(new Contact(input.confirmInput("first name"), input.confirmInput("last name"), input.confirmInput("address"), input.confirmInput("phone number"), input.confirmInput("DOB in dd/mm/yyyy format"), input.confirmInput("email")));
}

void updateExistingContact() {
    if (checkForContacts()) {
        displayContacts();
        try {
            updateContactFields(contactList.get(Integer.parseInt(input.confirmInput("contact choice")) - 1));
        } catch (Exception e) {
            System.out.println("No such contact");
        }
    }
}

boolean checkForContacts() {
    if (contactList.size() == 0) {
        System.out.println("There are no contacts yet");
        return false;
    } else {
        return true;
    }
}

void updateContactFields(Contact contact) {
    // logs and update calls
}

void showContact() {
    if (checkForContacts()) {
        displayContacts();
        Contact contact = null;
        try {
            contact = contactList.get(input.contactChoice() - 1);
        } catch (Exception e) {
            System.out.println("No such contact");
            showMenu();
        }
        printContactDetails(contact);
    }
}

void printContactDetails(Contact contact) {
    // lots of logs
}

void displayContacts() {
    System.out.println("Please select a contact");
    for (int i = 0; i < contactList.size(); i++) {
        System.out.println(i + 1);
    }
}
}

(Note: there's extra functionality here too)

To avoid calling methods from the static method main, you just:

  • Make an instance of the Main class in the main method
  • Call any methods from that instance of Main (e.g. main.displayContacts())
  • Now you only have to make things static where it's good practice

When should things be static?

I'm glad you asked: Let's say I have a list of contacts, and each of these contacts has several properties. In case they share a common property, the variable can be static to save memory.

class Contact {
    String name;
    static String country = "Arstotzka";
    int age;
    // and so on
}

If I have 10 Contact instances, the name variable will be assigned memory 10 times. On the other hand, country is static, so it's only given memory once, however many instances there are. It doesn't have to be static, but it's more efficient, memory-wise, to make it so.

Notes:

  • It can still be changed, but it's less likely to be changed than non-static variables.
  • Static variables must also be initialised with a value, as you are saying that the variable and its value is inherent to the class.

Class Methods

Class methods are used without instantiating the class, as was the case in Example 1. Main was never instantiated, so if I called any methods, they had to be class level instead of object level.

Example 3

class Contact {
    String name;
    static String country = "Arstotzka";
    int age;
    // and so on

    static void updateCountry() {
        country = "Republia";
    }
}

The static method in Example 3 updates the static variable country, so every instance of Contact will now have the string value 'Republia' instead of 'Arstotzka'.

Recap

  • Static variables are class level variables, so are inherited by instances, and must be initialised before making an instance
  • Static methods are class methods, and are called without the class being instantiated
  • If you want to use instance methods, you need to instantiate your class (just now made the connection between instance variables/methods and instances of classes)

This is far from exhaustive, but is information that would have saved me a lot of time and pain if I had done the research earlier.

Let me know your thoughts, whether you think this is clear and useful, or I've missed something big and made some bad assertions!

Discussion (0)