I'm creating an immutable representation of an "event" in my system, and thus for lists of owners passed in the constructor, I'd like to take a read only view of them. Further, if they pass in null for the list, I'd like to make a read-only empty list in that case.
Now, since Collections.unmodifiableList balks at null, I currently have this:
userOwners_ = Collections.unmodifiableList(userOwners != null
? userOwners
: new ArrayList<String>(0));
But that seems a bit ugly and inefficient. Is there a more elegant way to do this in Java?
Collections.emptyList(). But seriously, null should NPE.
An equally ugly, but marginally more efficient answer would be
userOwners_ = userOwners != null ?
Collections.unmodifiableList(userOwners) :
Collections.emptyList();
However there are a couple of other things to observe.
It appears that at some point, someone has decided to use null to represent an empty list. That is poor design ... and results in the need for special handling. Better to set it to either a new list, or emptyList() if you know the list is always empty.
If you haven't consciously decided that null is the way to represent an empty list, then that null is "unexpected" and you should juts let it throw an NPE so you can track down and fix the cause. (It could be a variable that you have assumed is initialized elsewhere ... but isn't. That's a bug.)
There is some confusion about whether you want a "read-only" list or an "immutable" list:
The unmodifiableList() method gives you a list that you cannot modify; i.e. it is "read only". But the original list can still be modified, and those changes will be visible via the "read only" wrapper.
If you want an "immutable" list (i.e. one that cannot be changed at all), you need to clone() the original list, and then wrap the clone using unmodifiableList().
Neither of these will make the elements of the list (the "owner" objects) immutable (if they are not already immutable).
The identifier userOwners_ is a code style violation in the most widely accepted / used Java style guide.
The resultant userOwners_ will still be mutable - any changes to userOwners will be part of userOwners_.
The right way to do this if you really want that member variable to be immutable:
private final List<String> userOwners;
public MyObject(List<String> userOwners){
this.userOwners = userOwners != null ? Collections.unmodifiableList(new ArrayList<String>(userOwners)) : Collections.emptyList();
}
As a minor point, your member variable naming isn't following Java style guidelines (userOwners_ is strange to those of us who read Java code on a regular basis)
To expand on what another poster wrote: Think really, really hard before you accept a null input to a public method (without throwing NPE). This sort of behavior can hide bugs - much better to fail fast and force the caller to think about what they are doing.
My preferred way would be using Guava:
this.userOwners = ImmutableList.copyOf(Preconditions.checkNotNull(userOwners));
Like tackline's answer, this also throws an exception rather than silently translating null into the empty list.
Unlike the other answers here, using ImmutableList.copyOf() ensures that the caller can't pass you a list that they can later mutate.
Related
FindBugs raises a bug called EI_EXPOSE_REP with the following description :
EI: May expose internal representation by returning reference to mutable object
Returning a reference to a mutable object value stored in one of the object's fields exposes the internal representation of the object. If instances are accessed by untrusted code, and unchecked changes to the mutable object would compromise security or other important properties, you will need to do something different. Returning a new copy of the object is a better approach in many situations.
class Person {
private String[] hobbies;
String[] getHobbies(){ return hobbies;}
void setHobbies(String[] hobbies){ this.hobbies = hobbies;}
}
I know some solutions:
getHobbies(){return hobbies.clone();}
use List instead of Array;
What I want to know is why just array raises this bug, a list doesn't have this problem? Why array is so different from other collections?
Findbugs (which is now replaced by Spotbugs) raises a security issue. It is not a bug since it doesn't create an unwanted behavior by itself. But this exposure of the internal data CAN create bugs later in caller methods.
You guessed it, there are two ways to protect your getter against exposure:
Return a copy of your array with Arrays.copyOf(..)
Convert it to an "Immutable" List with Collections.unmodifiableList(..) (you can also use List.of(..) since Java 9)
A List will raise a similar warning unless made unmodifiable.
It's a good practice to use Collections instead of Arrays unless you really have a good reason not to.
In some cases, when you have few writes and many reads, the Class CopyOnWriteArrayList is a great alternative to have a simple immutable list getter.
What I want to know is why just array raises this bug.
It's just a warning. Findbugs displays a severity level next to the report.
Exposure is a medium one for security, but low for bugs.
A list doesn't have this problem?
It does. An ArrayList is just an Array with an additional layer of abstraction.
Why array is so different from other collections?
An Array is a native type, while Collections are not.
The behavior is similar, but you have less control over an Array than you have over a Collection.
I got this issue for byte[] variable in my POJO class. If you want, you can suppress it using an annotation: #SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"})
I have a number of Java classes that use private sets or lists internally. I want to be able to return these sets/lists using a get...List() method.
The alternatives I am considering:
return a reference to the internal object
construct a new set/list and fill it up (this seems bad practice?)
use Collections.unmodifiableList(partitions);
Which of these is the most common / best way to solve this issue?
There are many aspects to consider here. As others already have pointed out, the final decision depends on what your intention is, but some general statements regarding the three options:
1. return a reference to the internal object
This may impose problems. You can hardly ever guarantee a consistent state when you are doing this. The caller might obtain the list, and then do nasty things
List<Element> list = object.getList();
list.clear();
list.add(null);
...
Maybe not with a malicious intention but accidentally, because he assumed that it was safe/allowed to do this.
2. construct a new set/list and fill it up (this seems bad practice?)
This is not a "bad practice" in general. In any case, it's by far the safest solution in terms of API design. The only caveat here may be that there might be a performance penalty, depending on several factors. E.g. how many elements are contained in the list, and how the returned list is used. Some (questionable?) patterns like this one
for (int i=0; i<object.getList().size(); i++)
{
Element element = object.getList().get(i);
...
}
might become prohibitively expensive (although one could argue whether in this particular case, it was the fault of the user who implemented it like that, the general issue remains valid)
3. use Collections.unmodifiableList(partitions);
This is what I personally use rather often. It's safe in the sense of API design, and involves only a negligible overhead compared to copying the list. However, it's important for the caller to know whether this list may change after he obtained a reference to it.
This leads to...
The most important recommendation:
Document what the method is doing! Don't write a comment like this
/**
* Returns the list of elements.
*
* #return The list of elements.
*/
public List<Element> getList() { ... }
Instead, specify what you can make sure about the list. For example
/**
* Returns a copy of the list of elements...
*/
or
/**
* Returns an unmodifiable view on the list of elements...
*/
Personally, I'm always torn between the two options that one has for this sort of documentation:
Make clear what the method is doing and how it may be used
Don't expose or overspecify implementation details
So for example, I'm frequently writing documentations like this one:
/**
* Returns an unmodifiable view on the list of elements.
* Changes in this object will be visible in the returned list.
*/
The second sentence is a clear and binding statement about the behavior. It's important for the caller to know that. For a concurrent application (and most applications are concurrent in one way or the other), this means that the caller has to assume that the list may change concurrently after he obtained the reference, which may lead to a ConcurrentModificationException when the change happens while he is iterating over the list.
However, such detailed specifications limit the possibilities for changing the implementation afterwards. If you later decide to return a copy of the internal list, then the behavior will change in an incompatible way.
So sometimes I also explicitly specify that the behavior is not specified:
/**
* Returns an unmodifiable list of elements. It is unspecified whether
* changes in this object will be visible in the returned list. If you
* want to be informed about changes, you may attach a listener to this
* object using this-and-that method...
*/
These questions are mainly imporant when you intent do create a public API. Once you have implemented it in one way or another, people will rely on the behavior in one or the other way.
So coming back to the first point: It always depends on what you want to achieve.
Your decision should be based on one thing (primarily)
Allow other methods to modify the original collection ?
Yes : return a reference of the internal object.
No :
construct a new set/list and fill it up (this seems bad practice? -- No. Not at all. This is called Defensive programming and is widely used).
use Collections.unmodifiableList(partitions);
return a reference to the internal object
In this case receiver end can able to modify the object's set or list which might not be requirement. If you allow users to modify state of object then it is simplest approach.
construct a new set/list and fill it up (this seems bad practice?)
This is example shallow copy where collection object will not be modifiable but object would be used same. So any change in object state will effect the actual collection.
use Collections.unmodifiableList(partitions);
In this case it returns an unmodifiable view of the specified list. This method allows modules to provide users with "read-only" access to internal lists. This could be used as best practice in situation where you want to keep object's state safe.
I believe the best solution is to return an unmodifiable list. If compared to the construction of a new list, returning an unmodifiable "proxy" of the original list may save the client from implicitly generating a lot of unnecessary lists. On the other hand, if the client really needs to have a modifiable list, let it create a new list by itself.
The problem you still have to consider is that the objects contained into the list may be modified. There is no cheap and easy const-correctness in Java.
The second option is definitely the right way to go.
The other two options depend on your requirements.
If you are not going to modify the list values outside the class, return an unmodifiable list.
otherwise, just return the reference.
Are there any major disadvantages of initializing a Java collection, e.g. ArrayList at the time of declaration such as :
List<String> strList = new ArrayList<String>();
The main purpose is to avoid the clutter of null checks while retrieving the elements.
Thanks
In general, the only disadvantage is that you may end up with a whole bunch of collections doing nothing and have unnecessarily done work to create the collection.
My personal preference is to assign a valid collection always unless there's a definite reason to avoid the memory and initialization overhead, such as within loops and other possible performance considerations. And if I was always ensuring the objects were initialized to non-null I would not then do redundant null-checks before using the collections.
The caution I would add is to make sure if you do use the collection that you use it and don't, in later code, replace it with an entirely new collection (that would indicate a probable design flaw). To enforce this you can declare the collection as final.
It depends on the use case:
Method body declaration - always ok.
Static field declaration - should always be ok.
Field declaration. There are two popular cases - when you always need it initialized or when it might be null. In the first case I make it final and prefer initializing in a constructor. If it might be null, I add a lazy getter and annotate it with #Nullable like this:
#Nullable
List<String> strList;
...
public final List getList(){
if(strList == null){
strList = new ArrayList();
}
return strList;
}
This technique helps me to eliminate ambiguity of field states.
You should almost always initialize right away. Just because it's initialized doesnt mean you shouldnt do null checks anymore. Creating the object and an if check have almost no effect on performance. Only when you're creating a list that has to copy objects from other collections or arrays
I was looking around for some elegant solution to removing null values from a List. I came across the following post, which says I can use list.removeAll(Collections.singletonList(null));
This, however, throws an UnsupportedOperationException, which I'm assuming is because removeAll() is attempting to do some mutative operation on the immutable singleton collection. Is this correct?
If this is the case, what would be a typical use of this singletonList? To represent a collection of size 1 when you're sure you don't want to actually do anything with the collection?
Thanks in advance.
It works like a charm:
List<String> list = new ArrayList<String>();
list.add("abc");
list.add(null);
list.add("def");
list.removeAll(Collections.singletonList(null));
System.out.println(list); //[abc, def]
Indeed Collections.singletonList(null) is immutable (which is unfortunately hidden in Java[1]), but the exception is thrown from your list variable. Apparently it is immutable as well, like in example below:
List<String> list = Arrays.asList("abc", null, "def");
list.removeAll(Collections.singletonList(null));
This code will throw an UnsupportedOperationException. So as you can see singletonList() is useful in this case. Use it when client code expects a read-only list (it won't modify it) but you only want to pass one element in it. singletonList() is (thread-)safe (due to immutability), fast and compact.
[1] E.g. in scala there is a separete hierarchy for mutable and immutable collections and API can choose whether it accept this or the other (or both, as they have common base interfaces)
To answer your actual question :
what would be a typical use of this singletonList? To represent a collection of size 1 when you're sure you don't want to actually do anything with the collection?
The typical use is if you have one element and want to pass it to a method that accepts a List, ie
public void registerUsers(List<User> users) {...}
User currentUser = Login Manager.getCurrentUser();
registerUsers(Collections.singletonList(currentUser));
The removeAll() is a special case for this.
Has your list been protected with
Collections.unmodifiableList(list)
Because if you have protected it and try to modify it later you get that error.
I just want to know for what java.util.Collections.checkedList() is actually used.
I have some code that I know is returning me a List<String> but it's being passed through a chain of messaging calls and returned to me as a java.io.Serializable. Is that checkedList call good for me to turn my Serializable into a List<String>? I know I can cast it to a java.util.List, but I'd rather not have to check each element and I'm not comfortable with assuming each element is a String.
It is used in part as a debugging tool to find where code inserts a class of the wrong type, in case you see that happening, but can't figure out where.
You could use it as part of a public API that provides a collection and you want to ensure the collection doesn't get anything in it of the wrong type (if for example the client erases the generics).
The way you could use it in your case is:
Collections.checkedList(
new ArrayList<String>(uncertainList.size()), String.class)
.addAll(uncertainList);
If that doesn't throw an exception, then you know you are good. That isn't exactly a performance optimized piece of code, but if the list contents are reasonably small, it should be fine.
Not quite:
Collections.checkedList will only decorate the list to prevent any future inserts with objects of the wrong class, it won't check all the elements that are already in the list.
However, you could make a new checkedList, and then call addAll and pass in the list you are unsure about - rather than writing the loop yourself.
A discussion of what checkedList could be used for is available in the documentation for checkedCollection. The reasons given are:
as a debugging aid (if someone has used an unchecked cast)
to ensure safety when passing a collection to be populated by third-party code.
You could use the following from google collections to check that the list does only contain strings:
Iterables.all(list, Predicates.instanceOf(String.class))