2

In order to achieve better immutability, should my API return java.lang.Iterable<T> or java.util.Enumeration<E>? Since Iterable's iterator has a remove() method, one could say Enumeration is the right choice, but the javadoc says "New implementations should consider using Iterator in preference to Enumeration".

I'm aware about unmodifiable collections, but in that case we still end up with collections that expose add and remove methods.

Any other options in Java?

asked May 17, 2016 at 10:51
5
  • would T.toArray() fit your parameters? An array T[] tArray has no methods. Is it the collection itself you want immutable or the objects referred to by the collection? Commented May 17, 2016 at 14:29
  • @scorpdaddy It is the collection itself. Primitive array could be an option if the client couldn't replace or remove elements from the structure, which is not true. One can ultimately do tArray[i] = new Object(). Commented May 17, 2016 at 20:24
  • Iterable has a much better integration than enumeration and Arrays (for each loop etc.), Commented May 20, 2016 at 7:19
  • Iterable<T> doesn't have a remove() method. Iterator<E> does. Commented Aug 15, 2016 at 13:32
  • @TulainsCórdova Thanks! I've updated the question. Commented Sep 16, 2016 at 9:07

3 Answers 3

3

As Brian says (and your reference to the docs), Iterables are much more common and what programmers are used to. Thus, use Iterable - it also allows to use the "foreach" statement, which does not support Enumeration.

As the unmodifiable collections are part of the base JDK, I would say that add/remove methods in the collection, and remove methods in the iterator, are exposed is just how it is in Java. It is instead common to simply document the API sufficiently, and throw UnsupportedOperationException where the user violates the API.

I would suggest the implementation of Tulains. However, throw an UnsupportedOperationException in remove instead of doing nothing. This communicates the interface correctly: you return an unmodifiable collection. This is also the behaviour of standard JDK classes (for instance emptySet() and unmodifiableList() from the Collections class).

For completeness, the implementation (with sufficient rep, I would have just commented on Tulains answer):

/* This is unmodifiable */
public class MyList<T> implements Iterable<T> {
 @Override
 public Iterator<T> iterator() {
 return new Iterator<T>() {
 @Override
 public boolean hasNext() {
 return false; // TODO: to implement
 }
 @Override
 public T next() {
 return null; // TODO: to implement
 }
 @Override
 public void remove() { 
 throw new UnsupportedOperationException();
 }
 };
 }
}

Note that I also moved the Iterator to an inner class to separate the collection and its iterator. This is also how it is done, for instance, for the class Collections.UnmodifiableList.

answered Aug 15, 2016 at 14:19
2

Iterable<T> doesn't have a remove() method. Iterator<E> does.

If you return an Enumeration the client would have to iterate it like this:

while(list.hasMoreElements()){
 e=nextElement();
}

If you want client code to be able to iterate it like this:

for(Element e; list){
 //do something with e
}

and keep it inmmutable at the same time, you should extend Iterator and Iterable, make remove() throw IllegalStateException if called, and return an object of that type:

public class MyList<T> implements Iterable<T>, Iterator<T> {
 @Override
 public Iterator<T> iterator() {
 return this;
 }
 @Override
 public boolean hasNext() {
 return false; // to implement
 }
 @Override
 public T next() {
 return null; // to implement
 }
 @Override
 public void remove() { 
 throw new IllegalStateException("I'm inmutable");
 }
 public static void main(String[] args) {
 MyList<String> l = new MyList<String>();
 for (String s: l){
 System.out.println(s);
 }
 }
}

You could return an object of type MyList.

answered Aug 15, 2016 at 13:51
3
  • As noted in the other answers, remove() should throw an exception, not do nothing. Otherwise a good answer. Commented Sep 14, 2016 at 16:01
  • @user949300 You are right. I changed the answer. Commented Sep 14, 2016 at 16:10
  • Thanks! I've updated the question to explain the Iterable's iterator has the remove() method. Commented Sep 16, 2016 at 9:09
1

I would normally expect an Iterable. It's a member of the Collections framework, and as such returning an Iterable will allow you to play nicely with other components.

I take your point re. immutability, though. There isn't a particularly nice means of returning a read-only collection. You could use Collections.unmodifiableList() but that won't provide a compile time check. The same applies to buidling a defensive copy.

Returning a Collection<? extends ElementType> if you're at liberty to return a collection rather than an iterator, will give you the compile-time safety. There's some more related discussion here

answered May 17, 2016 at 11:03
4
  • Well, the wildcard-approach only prevents adding and setting elements, but not removing if I recall correctly. And it does not clearly communicate the intent of being immutable which is why some static analysis tools flag it as an issue (e.g. Sonar squid:S1452). See also the accepted answer to stackoverflow.com/q/22815023/2513200 Commented May 17, 2016 at 12:22
  • I certainly agree with you that's not a perfect solution (including the concept of 'intent'). I don't think there's a perfect intuitive solution, unfortunately Commented May 17, 2016 at 12:26
  • Also, it does not even really prevent adding - you can still add null (admittedly, that's probably a minor issue in most szenarios, but...). Commented May 17, 2016 at 12:31
  • @BrianAgnew Good insight with Producer Extends approach, but still didn't help much compared to the other options. Thanks. Commented May 17, 2016 at 20:29

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.