8

I'm coming from a C++ background and was wondering on the immutable features of Java. Can return values of functions be specified as const? (meaning the returned value cannot be modified)

Also for bonus points, in c++ a function definition can be postfix'ed as const to state that the function will not modify any class level values. Is this also possible in Java? (meaning that a function by definition will not be able to change it's class state internally)

Thanks so much!

Jonathan Dunlap
  • 2,581
  • 3
  • 19
  • 22
  • 2
    Its worth nothing that in Java its much harder to have side effects with the language is much simpler, so you don't have to give the same hints to the optimisation of code. – Peter Lawrey Apr 28 '12 at 21:06
  • possible duplicate of [Why is there no Constant keyword in Java?](http://stackoverflow.com/questions/2735736/why-is-there-no-constant-keyword-in-java) – Mechanical snail Aug 06 '12 at 13:20

3 Answers3

9

No, Java's final is very different to C++'s const. You cannot do either of the things you asked.

To make an object immutable, it's more or less up to you to enforce it (as opposed to enlisting the compiler's help as in C++). From http://docs.oracle.com/javase/tutorial/essential/concurrency/imstrat.html:

The following rules define a simple strategy for creating immutable objects. ...

  1. Don't provide "setter" methods — methods that modify fields or objects referred to by fields.
  2. Make all fields final and private.
  3. Don't allow subclasses to override methods. The simplest way to do this is to declare the class as final. A more sophisticated approach is to make the constructor private and construct instances in factory methods.
  4. If the instance fields include references to mutable objects, don't allow those objects to be changed:
    • Don't provide methods that modify the mutable objects.
    • Don't share references to the mutable objects. Never store references to external, mutable objects passed to the constructor; if necessary, create copies, and store references to the copies. Similarly, create copies of your internal mutable objects when necessary to avoid returning the originals in your methods.
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • 6
    wow... that's terrible. It must be a lot of work in Java to protect state and such. Thanks for the weekend answer! – Jonathan Dunlap Apr 29 '12 at 05:55
  • 1
    @JonathanDunlap I believe the way to protect state is to return a new Object which is essentially a copy of what you want to return. – Troyseph Oct 06 '15 at 21:15
  • @Troyseph yes, but this can be very costly in terms of performance depending on size of the objects – Serhii Sep 15 '21 at 10:41
  • @Serhii That's just the price you pay in Java for protected state, I think there are patterns where you create a light copy (something that shares a reference to the base data) but it creates a deep copy if and when the user tries to modify it, C++ QString works like this I believe – Troyseph Sep 15 '21 at 16:16
  • @Troyseph interesting! how does that work? you cannot determine at compile time what the user is going to try changing can you? – Serhii Sep 16 '21 at 17:01
  • 1
    @Serhii You simply code into any "non-const" function a check to see if you are shared, and then make a deep copy of your data, flag yourself as unshared and modify away to your heart's content. A bit verbose, but there can be a good performance gain – Troyseph Sep 16 '21 at 18:15
1

No, there is actually no way to create immutable objects out of anywhere. If you want something immutable, it has to be immutable (final) along the whole tree.

e.g. the following example uses final in every place (except of the root) but is still not able to prevent any changes:

public class justAnInt {
    public int a = 0;
    public int b = 0;
}

// -----------------------------------

public class AliasProblem{
    private final justAnInt var = new justAnInt();
    final justAnInt getVar()
    {
        return var;
    }

    public static void main(String argv[])
    {
        final AliasProblemObject = new AliasProblem();
        final justAnInt localVar = AliasProblemObject.getVar();
        localVar.a = 19;
        System.out.println("object: " + object.getVar().a);
        System.out.println("local: " + localVar.a);
    }

}
TheTrowser
  • 363
  • 4
  • 14
0

I think you can return copy of object data for reading and hence protect them from being modified. But extra copy seems to be a great price for being immutable.

Vlad
  • 4,425
  • 1
  • 30
  • 39