Getters and Setters

From Juneday education
Jump to: navigation, search

Some thoughts about using getters and setters

What are they?

It is quite common to find examples online and in literature of classes with private instance variables together with public methods for accessing the values of the variables, and public methods for re-setting the values of the variables.

A method for accessing the value of a (potentially private) instance variable is called an accessor method, and a method for changing the value of a (potentially private) instance variable is called a mutator method. Often the examples give the accessor methods the name getVariableName() and the mutator methods the name setVariableName() (where "VariableName" is the name of the (potentially private) instance variable. Therefore, mutators are often also called setters, and accessors are often called getters.

An example (inspired by code from Columbia University) could be:

public class Time {
  private int hour;
  private int minute;
  private int second;

  public Time( int h, int m, int s ) {
    hour = h;
    minute = m;
    second = s;
  }

  // set the hour
  public void setHour( int h ) {
    hour = ( ( h >= 0 && h < 24 ) ? h : 0 );
  }


  public void setMinute( int m ) {
    minute = ( ( m >= 0 && m < 60 ) ? m : 0 );
  }

  public void setSecond( int s ) {
    second = ( ( s >= 0 && s < 60 ) ? s : 0 );
  }

  // Get Methods
  // get the hour
  public int getHour() { return hour; }
  
  // get the minute
  public int getMinute() { return minute; }

  // get the second
  public int getSecond() { return second; }

}

As a comment to the class above, think about an alternative Time class where second, minute and hour are public but they are also final (can't be re-assigned). If we remove the accessors and mutators from the class and do the validation in the constructor, having the final instance fields declared public is actually not a problem in terms of keeping the class invariant (the promise that we will always ever have a valid time). The constructor would typically throw an IllegalArgumentException (a runtime excpetion) if the caller violates the invariant (the rule that second and minute must be between 0 and 59 and that hour must be between 0 and 23). This behavior of the constructor (throwing an exception if it finds a violation) guarantees that there can never exist a Time object with a faulty state (an invalid time with for instance hour set to 25 or something stupid like that).

So the problem with the argument we often see together with examples of getters and setters, that "they are (the only) way to guarantee that wrong values can never enter the object". This is as you now see, not true at all. Even public fields (if they are final) can be guaranteed to hold the class invariant through the lifetime of the object (if the constructor throws an exception rejecting violations). Not only that, with public variables there is no need for neither accessors, nor mutators.

We don't recommend public instance variables (even final ones) however, but the above proves a point about the faulty reasoning behind mutators as the (only) way to guarantee invariants (check and verify values which must be valid according to some rules).

Doesn't every class have them?

No, not every class has getters and setters. Particularly, not every class has getters and setters. Even more particularly, not every class has getters and setters for every private instance variable!

The point we are trying to convey in this page, is focused on making you think about what you do, and what you read and what you hear. If you get the idea from somewhere (unfortunately there are numerous sources) that you should always make public getters and setters for your class' private instance variables, you should stop and think about why you would want that.

Granted, the setters from the example above are an improvement over public instance variables, because you can check that the value passed to the setters makes sense - you shouldn't allow the second value of a time to be greater than 59 for instance. The setter guarantees that (similar checks could be done in the constructor!).

But what you should think about is, once a Time object is created, do I really need a way to programmatically change the variables for second, minute and hour separately? Do I really want a Time object to be changed at all? Perhaps the only way for a Time object to change, should be by some other means, like ticking (increasing) a certain amount of seconds and letting that reflect on the other variables. Who knows, but it certainly merits thinking about.

We try to convince you here, that there is no automatic need for getters and setters for every private variable in every class.

There are many classes, for instance in the Java API, which do not have getters and setters for the private instance variables. Some classes do not have any setters at all, in fact. Instead some classes provide instance methods which creates a completely new object of the class, if someone wants to change what an object represents. We'll discuss this thing in Classes III.

To take a few examples of classes which lack getters and setters from the Java API, we could look at java.io.File for instance. The File class represent file and directory paths. It declares the following private instance variables:

   private final String path;
    private transient PathStatus status = null;
    private final transient int prefixLength;
    private volatile transient Path filePath;

But it does not declare the following getters:

getFilePath()
getPrefixLength()

From this we can realize that there is no rule that every private variable must have an accessor with a name starting with get followed by the variable name. In fact, there is no rule that every private variable must have an accessor method with any name at all.

The File class declares the following methods with a name starting with set:

    public boolean setLastModified(long time)
    public boolean setReadOnly()
    public boolean setWritable(boolean writable, boolean ownerOnly)
    public boolean setWritable(boolean writable)
    public boolean setReadable(boolean readable, boolean ownerOnly)
    public boolean setReadable(boolean readable)
    public boolean setExecutable(boolean executable, boolean ownerOnly)
    public boolean setExecutable(boolean executable)

As you can see, none of the methods named set-something has any of the private variables' names as part of its name. From this we can learn that there is no rule that every private variable must have a mutator called set and the variable name as the rest of the method name. In fact, there is no rule that every private variable must have a mutator method with any name at all.

At least, we can say that there is at least one class, in the Java API, whose private variables lack a getter and setter. In fact, this holds for most classes in the API. If you don't believe us, read the source code ;-)

The File class has been around in the Java API for quite some time.

Where do they come from?

Why do books and resources insist on showing classes where every single private instance variable has a corresponding getter and setter method? We have no idea. We suspect it is some kind of not-so-well-founded consensus based on some kind of feedback loop. We haven't tracked down the source of this idea, but we've seen it propagate to numerous books and online examples (including some examples on Oracle.com even).

It is not that we hate the idea, just that we do not like that such resources might give the readers the idea that this is a rule or something that you should do without hesitation. It is the knee-jerk reaction of writing getters and setters for every private variable we object to. If you have good reasons to provide both getters and setters, then there is no compelling argument (or consensus) for naming them exactly getVariable() and setVariable(). There might be much better names, in fact. But this is a matter of style and preferences. There is, however, no rule for neither having getters and setters, nor for what to name them if you choose to have them.

We have some theories as to where this comes from. One theory involves a standard for creating a certain type of classes for a certain type of objects called JavaBeans. In this standard, there is a rule (for technical reasons which have to do with dynamically creating classes and objects) that every private instance variable must have a corresponding getter and setter. But this standard should be seen, in our humble opinion, as an exception and not as a general rule for all the classes in the world.

Another theory we have, is that some applications used for creating Java programs (IDEs) add code for getters and setters automatically when you create private instance variables. Why they do this, is beyond our comprehension.

You may choose to include accessors and mutators in all your classes if you think it is a compelling idea which adds to the safety and usability of your classes. Just try to remember that this idea is not shared by every author of every book about Java.

What could be the problems with them?

If you think about it, the idea of having access modifiers such as public and private, is to hide implementation details behind private, and provide useful abstractions via what is public. If we make public getters and setters (especially if the getters and setters have exactly the same type as the private variable) we actually "leak" implementation details of the types for our private variables. We create a coupling between our choice of type (and even our name if you follow the crazy idea of the getters and setters "naming convention" to the letter) for our private variables and the users of our classes.

If we later decide to change the name or type of a private instance variable (which should remain an implementation idea), what should you do with the getters and setters? Change their signatures? Change the getters return type? Of course, you could keep the old version of the getters and setters and use type conversion (cast) between the old type and the new type of the private instance variable. But if you do, you are violating the idea of the getters and setters to reflect the name and type of the private variables. So this also proves that such an idea or convention is at least not future proof.

As we hinted above, quite a few classes do not even allow modification of the internal state of the object via methods. They instead return new objects if some client code (user of the class and objects) wants a new state reflected. There are many reasons why this is a good idea (see for instance Joshua Bloch, Effective Java, Item 15 "Minimize Mutability"). If you accept that for instance String, Integer, Double and many more classes are implemented like this, that at least shows that there cannot be a rule to provide mutators for every (or even any) private instance method.

What could we use instead, then? We refer to our chapter Classes III for a discussion on immutability. But put simply, you can set an objects initial state (set the private instance variables reflecting the state of the object) via parameters to the constructor, and only provide accessors for the values users of your class might need. If there is a need for changing some parts of the state, you can choose between making a mutator (with any name you like), or make the class immutable and instead return a reference to a new object of the same class which reflects the new state.

There are times when you definitely could argue for a getter or even a setter, but this should not be something you provide every private variable without thinking or seeing a strong need for (as with any public method).

Another problem even with accessors (getters) is that they can expose a mutable instance variable which is meant to be private and never changed (not even with a mutator/setter). Consider having a private ArrayList as an instance variable, and that this list is very sensitive and should not be changed by outsiders (people using your class). It is not enough to not write a mutator for this variable, because it is a reference variable. If you have an acceessor (getter) which returns this private reference variable, you are returning a reference to the actual ArrayList object, and ArrayLists are inherently mutable.

Someone could then do this in order to add an entry to the list, using only the accessor (getter):

objectRef.getList().add(aNewObjectReference);

In order to prevent such outrageous behavior, we must make sure that either the array list isn't mutable (it is not possible to add new elements to it), or rather return a reference to a copy of the list from the accessor (getter).

What do other people say?

This is a somewhat hot topic and people seem to have strong opinions about whether to have mutable objects or immutable objects. And people also seem to have strong opinions on the related question on whether to have getters and setters at all. We too have pretty strong opinions about this topic, but our opinions focus on the strange phenomenon that so many teachers, books and tutorials seem to (via their numerous example classes and sometimes also via direct recommendations) teach that private variables should (or even must in some extreme cases we've seen and heard) be accompanied by public accessors and mutators (often they give the impression also that they should have the get- and set- names).

In our humble opinion, this is harmful teaching because it is so simple to see that this is not a rule (and often not either a good idea). There are simply too many counter-examples and reasons for not doing this, so it should not be taught in our opinion (which as we said is a strong opinion).

For more opinions about this, see the following (if the pages linked here have discussions, they could be quite entertaining to read):

Use your favorite search engine to find even more fascinating opinions on the good or evil about setters and getters!

Remember, our opinion is not about them being evil or not (even though we see problems with them from some perspectives). Our opinion is that one should not give the impression that they always should be there (specially if you try to teach programming). There is nothing wrong with showing what they are and how to write them, but that should always be accompanied by a discussions about pros and cons. In our humble opinion. OK, maybe not so humble, but we try.

Summary

  • You don't have to write accessors and mutators for every private instance variable
  • The constructor works fine for setting the values of an object once and for all
  • If you want to write accessors and mutators, you should have thought about why
  • If you want to write accessors and mutators, you do not have to use the prefices get and set for the names of these methods
  • Mutators (or setters as they sometimes are called) are not the only way to prevent bad values entering an object's state
    • The constructor can validate values and abort the construction of the object using a so called "throwing of an exception"