17

I'm trying to set a List unmodifiable.

In my code, I have a method which returns a list.

This list shouldn't be modified, but I don't want to catch the exception returned by the unmodifiableList.

private List<T> listeReferenceSelectAll = null;
List<T> oListeRet = new ArrayList<T>();
oListeRet = listeReferenceSelectAll;
return new ArrayList<T>(oListeRet);

It is an existing code and I have to transform it to return an unmodifiable list, but if an "add" method has been called, no exception has to be caught.

First I have create a class which implements List to override "add" method to log the exception and not to catch it.

But I don't know how to correctly instantiate it...

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
user2346325
  • 201
  • 1
  • 2
  • 4
  • 1
    Assuming it's not homework, http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#unmodifiableList(java.util.List) – Patashu May 03 '13 at 09:59
  • 3
    It's very hard to understand the code snippet you've given as it appears to be partly in a method and partly not. It's also not clear what you mean by "i dont want to catch the exception" - which exception? Do you really mean you want a list which silently *ignores* any attempt to modify it? Ick! – Jon Skeet May 03 '13 at 09:59
  • 1
    Use the collections package, don't reinvent the wheel. – pcalcao May 03 '13 at 10:00
  • When you do oListeRet = listeReferenceSelectAll, you lose the reference to the array list you created. I suspect this not what you intend. – flup May 03 '13 at 10:03
  • @JonSkeet I understand your concern. But he didn't say that he wants to **silently** ignore attempts to modify the list. And I think he made a pretty good point on why exceptions are unacceptable here. In his "10 year old application" there are probably other ways to get developer's attention, like extensive error logs that are read by the maintaining developer every day. Therefore I find his minimally invasive approach to clean up code step by step very legitimate and actually quite smart. – Jonas Bötel Apr 30 '14 at 08:01
  • 1
    @LumpN: It still feels wrong to me. If you call `add` and it doesn't fail, but it also doesn't add the item to the list, that sounds like a recipe for disaster. – Jon Skeet Apr 30 '14 at 08:03

7 Answers7

74

You need java.util.Collections:

return Collections.unmodifiableList(oListeRet);

If you have to write your own, have that class implement the List interface and throw exceptions for the methods that modify contents.

duffymo
  • 305,152
  • 44
  • 369
  • 561
23

Collections.unmodifiableList

Returns an unmodifiable view of the specified list. This method allows modules to provide users with "read-only" access to internal lists. Query operations on the returned list "read through" to the specified list, and attempts to modify the returned list, whether direct or via its iterator, result in an UnsupportedOperationException. The returned list will be serializable if the specified list is serializable. Similarly, the returned list will implement RandomAccess if the specified list does.

Community
  • 1
  • 1
Achintya Jha
  • 12,735
  • 2
  • 27
  • 39
11

Java-9 provides a new methods to create unmodifiable/immutable List:

jshell> List<Integer> list = List.of(1,2,3);
list ==> [1, 2, 3]

jshell> list.add(10);
|  java.lang.UnsupportedOperationException thrown: 
|        at ImmutableCollections.uoe (ImmutableCollections.java:70)
|        at ImmutableCollections$AbstractImmutableList.add (ImmutableCollections.java:76)
|        at (#6:1)

List.of creates an immutable list containing an arbitrary number of elements.

Anton Balaniuc
  • 10,889
  • 1
  • 35
  • 53
8

Although the accepted answer addresses the request of omitting / swallowing the UnsupportedOperationException, there should be an explanation of why it's an undesirable practice.

1) The overall intent to swallow an exception is a contradiction of the "fail-fast" principle. Instead of finding and catching defects early they are just allowed to go "under the carpet" turning into time bombs.

2) Not throwing UnsupportedOperationException is a direct violation of List's contract which says:

Throws:
    UnsupportedOperationException - if the add method is not supported by this list.

So the proper answer to what is written in the question's title: "Unmodifiable List in java" should still be:

return Collections.unmodifiableList(oListeRet);
Alex Dmitriev
  • 3,664
  • 3
  • 29
  • 35
4

If you absolutely must do this, try to follow the contract specified by java.util.List in the list you are creating.

Your code would look something like

public class UnmodifiableArrayList<E>  extends ArrayList<E> {

    public UnmodifiableArrayList(Collection<? extends E> c) {
        super(c);
    }

    public boolean add(int index) {
        return false;//Returning false as the element cannot be added 
    }

    public boolean addAll(Collection<? extends E> c) {
        return false;//Returning false as the element cannot be added 
    }

    public E remove(int index) {
        return null;//Returning null as the element cannot be removed
    }
}

Add any more methods you need on the same lines. Just ensure that all the constructors and methods that might by used to modify in your code are overriden, so as to ensure the list is unmodifiable.

Using the Collections API is the cleaner and better way to do it, so use this way only if using Collections.UnmodifiableList does not satisfy your need.

And keep in mind this will be a nightmare while debugging so log as much as possible.

Aditya
  • 2,148
  • 3
  • 21
  • 34
  • 3
    @user2346325 you can't seriously accept this answer when all others list the correct "official" way to do it! – Sean Patrick Floyd May 03 '13 at 10:43
  • @SeanPatrickFloyd - I agree this is a very dirty way of doing it, so i mentioned it the end of the answer again to use Collections API as it is a standard way of doing it, and to use this approach only if there is no other way. – Aditya May 03 '13 at 10:58
  • I know it's not the good way to do it but the application is 10 years old and bad code is everywhere.Collections API can have bad side effects in the application context. I will keep the 2 solutions,test them, and wait till monday for a person who know the application pretty much well than me. – user2346325 May 03 '13 at 11:37
  • 6
    So you're going to compound the problem by adding more bad code? And please point out the "bad effects"? How are those more harmful than adding more bad code? – duffymo May 03 '13 at 11:44
  • "Collections API can have bad side effects in the application context" What on earth do you mean by that? – Sean Patrick Floyd May 03 '13 at 11:54
  • At the moment,the application doesnt allow to throw the exception from collection API nor discontinue the process. So I am obliged to find a solution that works without throwing an exception but that just doesnt allow to modify. So what I am looking for is a List which doesnt provide a "set" method. – user2346325 May 03 '13 at 12:29
  • 1
    By doing this you will introduce hidden bugs in your code anywhere the code is expecting the `add` method to work. In the original post there was a statement about logging the exception. If you are planning to migrate the code then logging the exception will help you find the places that need updating. If you don't plan to log instances where attempts are made to modify the list and later correct those lines of code... then I don't recommend silently ignoring requests to add/remove elements from the list! – Jason Oct 29 '13 at 17:41
  • 1
    this is not the correct way to do, please consider using Collections.unmodifiableList – phury Aug 04 '15 at 21:43
2

1) These lines make no sense

List<T> oListeRet = new ArrayList<T>();
oListeRet = listeReferenceSelectAll;

2) Use Collections.unmodifiableList.

return Collections.unmodifiableList(oListeRet);

You dont need to catch exception it may throw, they are all UnsupportedOperationException - RuntimeExceptions

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
-1

The comments about unmodifiable list are correct. Make a method accessor that calls Collections.unmodifiableList. However, you may want to just use an array like so, and use a list internally.

 public MyObject[] getObjects() {
    return (MyObject[]) mList.toArray();
 }
Joel Teply
  • 3,260
  • 1
  • 31
  • 21