15

I really admire java features and I don't want to give up using it for the next problem:

I have a class that might be inherited, and inside of it is a private ArrayList arr; So the setter function is ok , but the getter function return arr; returns the reference to that variable which anyone capable of editing that whole array which I don't want and private wouldn't make any sense !

In C++ I would just return const arr; and it would return constant reference to the variable.

I so much need the variable not to be cloned or manually copied because there are so many calculations that require to (READ ONLY the variable) WHY there is no const returning in java ???? is there any way I could escape copying ?

p.s (final ArrayList<Integer> arr;) isn't an option cause that array always changes size or element values.

If I couldn't find a fix to that I'm threatening to go back to C++ or make everything public and you should never get my software :D


EDIT: one more important question: Am I asking for something that's not good (Software engineering wise) I mean if JAVA creators thought of not having const reference (returning Read only references) then I must be asking for something that can be handled in other way. or my program design is wrong I'm so confused.

user229044
  • 232,980
  • 40
  • 330
  • 338
Ismail Marmoush
  • 13,140
  • 25
  • 80
  • 114
  • 10
    @GMan: I disagree. If something is a good idea in C++, then it is worth learning what the equivalent good idea is in other languages, if any. And if none, that teaches you something about both languages. If Bjarne Stroustrup hadn't been thinking about Simula while programming C, then we wouldn't have C++ ;-) The mistake would be to assume that if something is a good idea in C++, then it must necessarily be a good idea in all other languages. – Steve Jessop Nov 24 '10 at 01:13
  • @Steve: I disagree. Why not just drop the word 'equivalent'? "what the good idea is in other languages" You don't need to know any language before hand to learn the good ideas. It isn't going to get you to some different good idea, and can just lead you astray. So what advantage is there to day dream about a different language while trying to learn a new one? And I'll say inventing a new language is a far different task than learning one. – GManNickG Nov 24 '10 at 01:18
  • 3
    @GMan: The advantage of daydreaming is that if ismail wasn't familiar with const references in C++, then it wouldn't so easily occur to him to restrict his callers to read but not write his ArrayList. Granted, he could have mentioned C++ a lot less in the question, and focussed on the core task which const references actually accomplish. I think there's a lot to be gained from knowing multiple languages and paradigms, and seeing what can be translated and what can't. I don't think Stroustrup set out to invent a new language - he had to when C didn't do what he wanted. – Steve Jessop Nov 24 '10 at 01:24
  • 6
    I actually think this question was quite well asked. Aside from the threat to give up on Java (humorous, but I wouldn't *entirely* rule it out as a fix), it clearly is asking what the Java solution is to a problem which the questioner happens to know how to solve in C++, and therefore expects might well have a solution in Java. And indeed it does have one, although the questioner is open to the possibility that it doesn't need one. To me that's *exactly* the right way to apply programming experience to learning a new language - have an idea but if it won't go, don't force it. – Steve Jessop Nov 24 '10 at 01:29
  • I do think the `[c++]` tag is odd though. The question is about Java, and just because it references a feature of C++ doesn't really make it C++-tag-worthy, does it? Apart from that, I think @Steve is right that *mentioning* C++ is fine. – jalf Nov 24 '10 at 06:50
  • @Steve Jessop & Gman, I really enjoyed reading your comments, I even read them twice :D , when two experts debate even on the simplest thing the out come is enlightening. – Ismail Marmoush Nov 24 '10 at 09:28
  • @Ismail Marmoush, so what's the decision, do you stay with us? :) sorry for off-topic. – andbi Nov 24 '10 at 21:50
  • @Osw hahaha :D yes after lots of reading I discovered they both are great tools and one should really know both well to decide the best language for his next project and I guess It will be Java this time :) – Ismail Marmoush Nov 26 '10 at 18:09

4 Answers4

23

Wrap the return value with java.util.Collections.unmodifiableList. It does not make a copy of the data, but wraps the original list, and delegates read-only operations to the underlying list. Operations which would modify the list are rejected at runtime via UnsupportedOperationException.

Your

return arrayList;

becomes

return Collections.unmodifiableList(arrayList);

Unfortunately the read-only constraints won't be enforced by the compiler. They will, however, be enforced at runtime.

You also have available to you: unmodifiableSet, unmodifiableMap, unmodifiableCollection, unmodifiableSortedSet, and unmodifiableSortedMap. And if these are not enough, you can still take inspiration from this general design approach, and create your own custom read-only wrapper classes.

Mike Clark
  • 10,027
  • 3
  • 40
  • 54
  • "create your own custom read-only wrapper classes" - I started reimplementing the unmodifiable collections once (mainly as a code size optimization). Turned out the non-javac compiler I was using had a limit on the total number of inner classes per source file. Nobody had ever hit it before. Not to say you can't do it, but compared with implementing a const-correct class in C++, read-only wrappers in Java need more to justify the effort. – Steve Jessop Nov 24 '10 at 11:26
  • *"Not to say you can't do it, but compared with implementing a const-correct class in C++, read-only wrappers in Java need more to justify the effort."* Steve, I tend agree. In my latest project, it's been deemed acceptable to use "read-only by documentation contract, and causing problems by breaking the contract is the class consumer's fault, not the class' fault." This will definitely not be acceptable for all people in all situations, though. In some critical cases, we pass/return by copy instead of reference. I do miss `const` at times, but we get along alright without it. – Mike Clark Nov 24 '10 at 17:38
2

:) You have several options:

  • Don't expose getter, provide only methods which are allowed to call, e.g.

    public void addToList(Object arg) { this.arr.add(arg);}

  • Return immutable object:

    public List getArr() { return Collections.unmodifiableList(this.arr); }

Community
  • 1
  • 1
andbi
  • 4,426
  • 5
  • 45
  • 70
0

You could also use Google Guava's immutable collections. In this case, you would store an ImmutableList in your field.

Of course, if your class needs to modify this list internally, using ImmutableList might turn out to be a bad idea, since you'll need to create a new ImmutableList instance and reassign it to the field each time...

But it's perfect when you know the List won't change after object construction.

Immutable example (list won't change after object construction)

@Immutable
public final class Foo {

    @Nonnull
    private final ImmutableList<String> list;

    public Foo(@Nonnull List<String> list) {
        // you could also compute the appropriate list here
        // before assigning it to the field
        this.list = ImmutableList.copyOf(list);
    }


    public ImmutableList<String> getList() {
        return list;
    }
}

Mutable example (list may only be modified using the setter)

public class Foo {

    @Nonnull
    private ImmutableList<String> list = ImmutableList.of();

    public ImmutableList<String> getList() {
        return list;
    }

    public void setList(@Nonnull List<String> list) {
        this.list = ImmutableList.copyOf(list);
    }
}

Remarks

  • I know it's often advised to make methods return the most generic type possible (List in this case), but I prefer to declare my getter's return type as an ImmutableList, because it acts as documentation (no need to document the returned list's immutability in the Javadoc) and as an API contract. It's like saying "I guarantee this list to be immutable, you do not have to worry or defensively copy it". And it is very concise.
  • ImmutableList.copyOf() is great, since it automatically rejects null lists (by throwing NullPointerException). It also rejects null elements. And it won't copy the source list if it's already an ImmutableList, which avoids useless object instantiation.
  • In the second example, I initialize the field to an empty ImmutableList using ImmutableList.of(), because it's a good practice to return empty collections instead of null values (Null Object pattern). You might think that this creates needless object instantiation, but ImmutableList.of() actually returns a singleton.
Etienne Neveu
  • 12,604
  • 9
  • 36
  • 59
-1

unmodifiableList is definitely the answer.

fastcodejava
  • 39,895
  • 28
  • 133
  • 186