Muhammad Khojaye is an experienced consultant who has worked on both large scale Agile development projects for top financial clients and public sector innovative research and development projects. In his spare time, Muhammad likes to work on independent open source programs. Muhammad is a DZone MVB and is not an employee of DZone and has posted 13 posts at DZone. You can read more from them at their website. View Full User Profile

Getter Setter: To Use or Not to Use

10.19.2010
| 30389 views |
  • submit to reddit

Java Getter Setter

Why do we keep instance variables private? We don’t want other classes to depend on them. Moreover it gives the flexibility to change a variable’s type or implementation on a whim or an impulse. Why, then do programmers automatically add getters and setters to their objects, exposing their private variables as if they were public?

Accessor methods

Accessors (also known as getters and setters) are methods that let you read and write the value of an instance variable of an object.

public class AccessorExample {
private String attribute;

public String getAttribute() {
return attribute;
}

public void setAttribute(String attribute) {
this.attribute = attribute;
}
}

Why Accessors?

There are actually many good reasons to consider using accessors rather than directly exposing fields of a class

Getter and Setters make APIs more stable. For instance, consider a field public in a class which is accessed by other classes. Now later on, you want to add any extra logic while getting and setting the variable. This will impact the existing client that uses the API. So any changes to this public field will require change to each class that refers it. On the contrary, with accessor methods, one can easily add some logic like cache some data, lazily initialize it later. Moreover, one can fire a property changed event if the new value is different from the previous value. All this will be seamless to the class that gets value using accessor method.

Should I have Accessor Methods for all my fields?

Fields can be declared public for package-private or private nested class. Exposing fields in these classes produces less visual clutter compare to accessor-method approach, both in the class definition and in the client code that uses it.

If a class is package-private or is a private nested class, there is nothing inherently wrong with exposing its data fields—assuming they do an adequate job of describing the abstraction provided by the class.

Such code is restricted to the package where the class is declared, while the client code is tied to class internal representation. We can change it without modifying any code outside that package. Moreover, in the case of a private nested class, the scope of the change is further restricted to the enclosing class.

Another example of a design that uses public fields is JavaSpace entry objects. Ken Arnold described the process they went through to decide to make those fields public instead of private with get and set methods here

Now this sometimes makes people uncomfortable because they've been told not to have public fields; that public fields are bad. And often, people interpret those things religiously. But we're not a very religious bunch. Rules have reasons. And the reason for the private data rule doesn't apply in this particular case. It is a rare exception to the rule. I also tell people not to put public fields in their objects, but exceptions exist. This is an exception to the rule, because it is simpler and safer to just say it is a field. We sat back and asked: Why is the rule thus? Does it apply? In this case it doesn't.

Private fields + Public accessors == encapsulation

Consider the example below

public class A {
public int a;
}
Usually this is considered bad coding practice as it violates encapsulation. The alternate approach is
public class A {
private int a;

public void setA(int a) {
this.a =a;
}

public int getA() {
return this.a;
}
}

It is argued that this encapsulates the attribute. Now is this really encapsulation?

Fact is, Getters/setters have nothing to do with encapsulation. Here the data isn't more hidden or encapsulated than it was in a public field. Other objects still have intimate knowledge of the internals of the class. Changes made to the class might ripple out and enforce changes in dependent classes. Getter and setter in this way are generally break encapsulation. A truly well-encapsulated class has no setters and preferably no getters either. Rather than asking a class for some data and then compute something with it, the class should be responsible to compute something with its data and then return the result.

Consider an example below,

public class Screens {
private Map screens = new HashMap();

public Map getScreens() {
return screens;
}

public void setScreens(Map screens) {
this.screens = screens;
}
// remaining code here
}

If we need to get a particular screen, we do code like below,

Screen s = (Screen)screens.get(screenId); 

There are things worth noticing here....

The client needs to get an Object from the Map and casting it to the right type. Moreover, the worst is that any client of the Map has the power to clear it which may not be the case we usually want.

Alternative implementation of the same logic is:

public class Screens {
private Map screens = new HashMap();

public Screen getById(String id) {
return (Screen) screens.get(id);
}
// remaining code here
}

Here the Map instance and the interface at the boundary (Map) are hidden.

Getters and Setters are highly Overused

Creating private fields and then using the IDE to automatically generate getters and setters for all these fields is almost as bad as using public fields.

One reason for the overuse is that in an IDE it’s just now a matter of few clicks to create these accessors. The completely meaningless getter/setter code is at times longer than the real logic in a class and you will read these functions many times even if you don't want to.

All fields should be kept private, but with setters only when they make sense which makes object Immutable. Adding an unnecessary getter reveals internal structure, which is an opportunity for increased coupling. To avoid this, every time before adding the accessor, we should analyze if we can encapsulate the behavior instead.

Let’s take another example,

public class Money {
private double amount;

public double getAmount() {
return amount;
}

public void setAmount(double amount) {
this.amount = amount;
}

//client
Money pocketMoney = new Money();
pocketMoney.setAmount(15d);
double amount = pocketMoney.getAmount(); // we know its double
pocketMoney.setAmount(amount + 10d);
}

With the above logic, later on, if we assume that double is not a right type to use and should use BigDecimal instead, then the existing client that uses this class also breaks.

Let’s restructure the above example,

public class Money {
private BigDecimal amount;

public Money(String amount) {
this.amount = new BigDecimal(amount);
}

public void add(Money toAdd) {
amount = amount.add(toAdd.amount);
}

// client
Money balance1 = new Money("10.0");
Money balance2 = new Money("6.0");
balance1.add(balance2);

}

Now instead of asking for a value, the class has responsibility to increase its own value. With this approach, the change request for any other datatype in future requires no change in the client code. Here not only the data is encapsulated but also the data which is stored, or even the fact that it exist at all.

Conclusions

Use of accessors to restrict direct access to field variable is preferred over the use of public fields, however, making getters and setter for each and every field is overkill. It also depends on the situation though, sometimes you just want a dumb data object. Accessors should be added for field where they're really required. A class should expose larger behavior which happens to use its state, rather than a repository of state to be manipulated by other classes.

More Reading

http://c2.com/cgi/wiki?TellDontAsk

http://c2.com/cgi/wiki?AccessorsAreEvil


From http://muhammadkhojaye.blogspot.com/2010/10/getter-setter-to-use-or-not-to-use.html 

Published at DZone with permission of Muhammad Khojaye, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Alexandru Repede replied on Tue, 2010/10/19 - 2:09am

finally, some brains !

 this is OOP (fields representing a hidden state + methods as inter-object communication representing the contract); next step: design patterns, design principles... (um, getting closer to idiomatic code)

thanks for the post and the nice "More Reading" section

 

 

 

Carlos Hoces replied on Tue, 2010/10/19 - 3:52am

Sometimes, mostly when decoupling, it is needed to get and set full collections out of simple data classes. This is commonly used with libraries like Eventbus, or NetBeans Platform Lookup.

In these cases, an encapsulation approach could be something like this:

<code>

public class TestClass {

    private Map<Integer, String> map;
    private List<Integer> list;

    public List<Integer> getList() {
        return list == null ? null : Collections.checkedList(list, Integer.class);
    }

    public void setList(List<Integer> list) {
        this.list = new ArrayList<Integer>(2 * list.size());
        this.list.addAll(list);
    }
   
    public Map<Integer, String> getMap() {
        return map == null ? null : Collections.checkedMap(map, Integer.class, String.class);
    }

    public void setMap(Map<Integer, String> map) {
        this.map = new HashMap<Integer, String>(2 * map.size());
        this.map.putAll(map);
    }
}

</code>

Martijn Verburg replied on Tue, 2010/10/19 - 5:49am

Great article, was good food for thought. I've been guilty in the past at times of hitting that auto-generate option, swapping to TDD actually stopped me from doing that and is doubly justified after reading articles like this one. Will send this round my team :) Cheers, Martijn (@java7developer - twitter)

Robert Saulnier replied on Tue, 2010/10/19 - 7:26am

Using private fields and public accessors does not have to give intimate knowledge of the class' internals. In your example, because the field "a" is encapsulated, we are able to change its type without breaking outside code.
public class A
{
  private String a;
  
  public void setA(int a) {
    this.a = String.valueOf(a);
  }
  
  public int getA() {
    return Integer.parseInt(a);
  }
}
The problem with getters and setters is abuse.

Carlos Hoces replied on Tue, 2010/10/19 - 8:11am

Same as above, without changing type:

<code>

public class TestClass {

    private int number;

    public int getNumber() {
        return Integer.valueOf(number);
    }

   public void setNumber(int number) {
        this.number = Integer.valueOf(number);
    }
}

</code>

Josh Marotti replied on Tue, 2010/10/19 - 9:58am

If you do NOT make public accessors, I'd urge everyone to make protected accessors.  Do it... for your childrens sake!!  ;)

 

Quick nitpick: immutable objects should have the fields set to private, so setters will actually cause a compile time error.

Chris Kelly replied on Tue, 2010/10/19 - 10:40am in response to: Josh Marotti

Surely you mean final not private for immutable objects.  IMHO immutable objects would not have setters anyway. 

 

You build it, you're stuck with it :)

Chris Kelly replied on Tue, 2010/10/19 - 10:48am

Great article. Sometimes people say they understand OO but you find they still code by passing around POJOs with accessor methods.

OO is really about passing behaviour around not state.  I guess this is a by-product of living in a J2EE world :).

 To paraphrase JFK, 'Ask not what you can do to your objects, but rather ask what your objects can do for you'

Alessandro Santini replied on Tue, 2010/10/19 - 10:53am

Nice one, Muhammad.

I insist that having a unform way of accessing fields/properties (à-la C# for instance, excluding its caveats) would take many problems away.

Having said that, thanks God someone pointed out that wrapping a field with an accessor/mutator is *NOT* encapsulation.

Josh Marotti replied on Tue, 2010/10/19 - 2:24pm in response to: Chris Kelly

Geez, I fubar'ed that up.


Yes, the fields should be FINAL not private.  Whoops!

Joseph Hirn replied on Thu, 2010/10/21 - 8:26pm

Let's say you have a field where today the access is direct. No business logic is needed to modify the field so let's make it public. Now everyone just does Object.field = foo accessing the object directly and we have fewer lines of java code to worry about.

Now let's say all of a sudden, there are new business rules or validations that you want to impose on that field. You now have to go around changing everywhere it is called in order to use the setter. This is why it is encapsulation. The object is responsible for modifying its state.

Sure the base case doesn't make sense but there is a reason why it is a convention. Java isn't able to override direct access like Scala. Groovy manages this by actually generating setters/getters under the hood. Java on the other hand has to rely on this. Yes it is noise, but like everything in Java it has a purpose. Very bad idea to NOT use them just because they are noisy.

FYI, most setters/getters that do direct access are just inlined by the JVM anyways so there isn't any runtime overhead.

D Fens replied on Fri, 2010/10/22 - 5:09pm

Fields should be private. Reason: allow internal logic changes later on without breaking expected client code.

Example:

public class Student {
  private int age;
  public void setAge(int age) {
    this.age = age;
  }
}

If later you find some user abusing this field by setting the field to -9999, then you can simply change it to the following without breaking expected client code:

public class Student {
  private int age;

  public void setAge(int age) {
    if (age < 0)
      throw new IllegalStateException("age should be 0 or higher");
      this.age = age;
  }
}

It will break code for users that set age to -9999, but that is an unexpected value that is wrong anyway. But it won't break expected code.

Muhammad Khojaye replied on Sun, 2010/10/24 - 12:38am

Thanks so much for the kind words. I'm so glad you people enjoyed it.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.