4

I was wondering why the final modifier is not used with getters and setters?

Why do this:

private int x;

public void setX(int x) 
{ 
  if(x >= 1) throw new IllegalArgumentException("X must be lower than 1");
  this.x = x; 
}

Instead of this:

private int x;

public final void setX(int x) 
{ 
  if(x >= 1) throw new IllegalArgumentException("X must be lower than 1");
  this.x = x; 
}

It does not improve the encapsulation? I have been trying to clarify it with google but I had not luck.

Thanks by advance.

fabian
  • 80,457
  • 12
  • 86
  • 114
jmb95
  • 97
  • 1
  • 2
  • 9
  • 1
    It all depends. Are you planning to make POJOs? – Sotirios Delimanolis Aug 15 '14 at 15:32
  • 1
    The best encapsulation is to avoid getters and setters (often possible) and try to follow the Tell, Don't ask philosophy. – Mik378 Aug 15 '14 at 15:32
  • Does [this](http://stackoverflow.com/questions/4012167/java-final-modifier) ("Java final modifier" question @stackoverflow)help to answer your question? – Stefan Freitag Aug 15 '14 at 15:33
  • It makes sense to make a getter `final` if the POJO aimed to be immutable. – Mik378 Aug 15 '14 at 15:33
  • 6
    `final` modifier will disable sub classes to override that method. You should only use it if you want this design, but it depends. There's no specific answer. Also, for code optimization, leave that to JIT unless proven by a profiler that this code will in effect behaves better. – Luiggi Mendoza Aug 15 '14 at 15:34
  • see how many `final` methods you can find in the JDK, then decide if you think it's a good idea. – Alnitak Aug 15 '14 at 15:41
  • @Mik378: if you make an immutable object, there shouldn’t be a setter at all, so the question does not apply, however, it is strongly recommended to make the *entire class* `final` for immutable objects, so you don’t need to think about the getters…. – Holger Aug 15 '14 at 16:36
  • @Holger : "It makes sense to make a getter final if the POJO aimed to be immutable." => I didn't mention "setter". – Mik378 Aug 15 '14 at 16:42
  • @Holger Yes of course. But the meaning of my sentence was implicit: "It would make better sense to make a getter final (if not the class) rather than the setter", this latter being in the OP. – Mik378 Aug 15 '14 at 16:54
  • @Mik378: then the “if the POJO aimed to be immutable” was misleading. I fully agree with “It makes sense to make a getter `final`”… – Holger Aug 15 '14 at 17:01
  • @Holger You're right. I should have be more clear. – Mik378 Aug 15 '14 at 17:01

4 Answers4

10

One reason that you may want to leave a setter non-final is to let subclasses make their own, stricter, argument checks:

public class Subclass extends Superclass {
    public void setX(int x) { 
        if(x >= 0) throw new IllegalArgumentException("X must be negative");
        super.setX(x); 
    }
}

Of course this breaks Liskov Substitution Principle, because a subclass strengthens a precondition in a subtype.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • and the _main_ reason is that you simply don't know in advance whether a derived class might want to do this, so unless you have _very good reason_ don't make your setter `final`. non-final should be the default. – Alnitak Aug 15 '14 at 15:37
  • On the other hand, this also allows the sub-class to make less strict checks, which might interfere with some logic of the super class, so this argument can go both ways. – Eran Aug 15 '14 at 15:43
  • 2
    @Eran No, it does not let subclasses to weaken the check: if you call `super.setX(x);` with a value that does not pass the check in the base, you're going to end up with an exception (reflection lets you beat the check, but reflection can let you do lots of bad things, so I'll not talk about it here). You could provide your own storage for `x` because `int x` in the base is private, but that is generally a very bad thing to do. – Sergey Kalinichenko Aug 15 '14 at 15:47
  • 2
    This is a very good way to potentially break Liskov Substitution Principle... A (professional) developer shouldn't do that. – Mik378 Aug 15 '14 at 15:49
  • @dasblinkenlight Agreed, as long as `x` is private in the super-class, you must call super.setX to set it. – Eran Aug 15 '14 at 15:50
  • 1
    Note that if you mark the getter as `final`, overriding the setter can 't break the invariants of the superclass, apart from the one that says `getX()` invoked after `setX()` should return the new value. It won't leave the class in an internally inconsistent state though. – biziclop Aug 15 '14 at 16:00
  • @Alnitak I actually think *public* members/types should be final/sealed by default, unless you think there'll be a good reason for others to need to extend a specific member/type. Programming for extensibility is hard. I could elaborate on this, but I could never put it better than Eric Lippert, so here's a good read: [Why Are So Many Of The Framework Classes Sealed?](http://blogs.msdn.com/b/ericlippert/archive/2004/01/22/61803.aspx?PageIndex=2) – dcastro Aug 15 '14 at 21:54
1

The purpose of a final method in Java, is that it cannot be overridden or hidden by subclasses. Hence if you need that functionality for your getters / setters, it's perfectly fine to make them final, else there is no purpose for doing so.

Gio
  • 3,242
  • 1
  • 25
  • 53
0

I would strictly avoid setters when there may be another more robust possibility:

You may want to provide a setter in case you want to mutate a field.

Issue you mentioned:

What if a developer breaks the validation rules I provided, by overriding the setter...Should we go with final keyword?

I would say: "Dissuade him to do so".

Indeed, declaring a setter is like saying to the world:
"You can provide me some field value and then you can do your own thing with me !" => procedural code

"Tell! Don't ask" philosophy would say:
"Client, tell me what to do, I will do."
And in general, your main "complex" logic would be in the main public api of the POJO.

I doubt that a developer would be tempted to override the full logic of a POJO without risking complete bad behaviors..

So, for instance, instead of declaring an opened setter to any value, force the value to be passed on the main method, so that you can control the flow:

public void computeWith(int x) {
  if(x <= 0) throw new IllegalArgumentException("X must be superior to 0");
  //code computing here.
}

You will notice that some fields might even not be needed any more in the POJO with this way of doing.

To sum up: It's easy to override a poor validation rule...but risky for a behaviour.

Just my 2 cents.

Mik378
  • 21,881
  • 15
  • 82
  • 180
-1

There are arguments both ways but if you make methods final (of any sort, not just getters or setters), somewhere down the line another developer will cursing you. It's very hard to predict how your class will be used in the future and restricting it by making it final usually makes like more difficult for a future developer.

eg some poor soul has got to integrate your code with a new application the company has just bought. It's 3pm on Friday afternoon and the demo is due on Monday morning. If only they could override a getter, they could force it to return a wrapped object from the new application and things would work. If that getter is final, they have to start changing, testing may be releasing your code so they end up working over the weekend.

So have some sympathy with future developers and don't make methods final unless you are really really sure. Even then I wouldn't bother.

Another use specifically for non-final getters is testing. It can be very convenient, particularly during integration tests with less than perfect code, to override a getter to inject a test instance of a class.

matt helliwell
  • 2,574
  • 16
  • 24