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
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"})
Is it possible to find out if some a list is fixed size or not?
I mean, for example this code:
String[] arr = {"a", "b"};
List<String> list = Arrays.asList(array);
returns fixed size List backed by an array. But is it possible to understand programmatically if List is fixed-size or not without trying to add/remove elements and catching the exception? For example:
try {
list.add("c");
}
catch(UnsupportedOperationException e) {
// Fixed-size?
}
A list created from a String[] by
List<String> list = Arrays.asList(array);
will have Arrays as enclosing class, while one created by for example new ArrayList() won't have the enclosing class. So the following should work to check if the List was produced as a result of calling Arrays.toList():
static <T> boolean wasListProducedAsAResultOfCallingTheFunctionArrays_asList(List<T> l) {
return Arrays.class.equals(l.getClass().getEnclosingClass());
}
Beware that this method relies on undocumented behavior. It will break if they added another nested List subclass to the Arrays class.
Is it possible to find out if some list is fixed size or not?
In theory - No. Fixed sizedness is an emergent property of the implementation of a list class. You can only determine if a list has that property by trying to add an element.
And note that a simple behavioral test would not reliably distinguish between a fixed sized list and a bounded list or a list that was permanently or temporarily read-only.
In practice, a fixed sized list will typically have a different class to an ordinary one. You can test the class of an object to see if it or isn't a specific class. So if you understand what classes would be used to implement fixed sized lists in your code-base, then you can test if a specific list is fixed sized.
For example the Arrays.asList(...) method returns a List object whose actual class is java.util.Arrays.ArrayList. That is a private nested class, but you could use reflection find it, and then use Object.getClass().equals(...) to test for it.
However, this approach is fragile. Your code could break if the implementation of Arrays was modified, or if you started using other forms of fixed sized list as well.
No.
The List API is identical regardless of whether a List is expandable or not, something that was deliberate.
There is also nothing in the List API that allows you to query it to determine this feature.
You can't completely reliably determine this information by reflection, because you will be depending on internal details of the implementation, and because there is an unbounded number of classes that are potentially fixed-size. For example, in addition to Arrays.asList, there is also Arrays.asList().subList, which happens to return a different class. There can also be wrappers around the base list like Collections.checkedList, Collections.synchronizedList and Collections.unmodifiableList. There are also other fixed-size lists: Collections.emptyList, Collections.singletonList, and Collections.nCopies. Outside the standard library, there are things like Guava's ImmutableList. It's also pretty trivial to hand-roll a list for something by extending AbstractList (for a fixed-size list you need only implement the size() and get(int) methods).
Even if you detect that your list is not fixed-size, the specification of List.add allows it to refuse elements for other reasons. For example, Collections.checkedList wrappers throw a ClassCastException for elements of unwanted type.
And even if you know your list is expandable, and allows arbitrary elements, that doesn't mean you want to use it. Perhaps it's synchronized, or not synchronized, or isn't serializable, or it's a slow linked list, or has some other quality that you don't want.
If you want control over the type, mutability, serializability, or thread-safety of the list, or you want to be sure that no other code has kept a reference to it, the practice is that you create a new one yourself. It's not expensive to do so when unnecessary (memcopies are blazing fast), and it lets you reason more definitely about your code will actually do at runtime. If you'd really like to avoid creating unnecessary copies, try whitelisting instead of blacklisting list classes. For example:
if (list.getClass() != ArrayList.class) {
list = new ArrayList<>(list);
}
(Note: That uses getClass instead of instanceof, because instanceof would also be true for any weird subclasses of ArrayList.)
There are immutable collections in java-9, but there is still no common #Immutable annotation for example or a common marker interface that we could query to get this information.
The simplest way I can think of would be simply to get the name of the class of such an instance:
String nameList = List.of(1, 2, 3).getClass().getName();
System.out.println(nameList.contains("Immutable"));
but that still relies on internal details, since it queries the name of the common class ImmutableCollections, that is not public and obviously can change without notice.
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.
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.
Say you are adding x number of objects to a collection, and after or before adding them to a collection you are modifying the objects attributes. When would you add the element to the collection before or after the object has been modified.
Option A)
public static void addToCollection(List<MyObject> objects) {
MyObject newObject = new MyObject();
objects.add(newObject);
newObject.setMyAttr("ok");
}
Option B)
public static void addToCollection(List<MyObject> objects) {
MyObject newObject = new MyObject();
newObject.setMyAttr("ok");
objects.add(newObject);
}
To be on the safe side, you should modify before adding, unless there is a specific reason you cannot do this, and you know the collection can handle the modification. The example can reasonably be assumed to be safe, since the general List contract does not depend upon object attributes - but that says nothing about specific implementations, which may have additional behavior that depends upon the object's value.
TreeSet, and Maps in general do no tolerate modifying objects after they have been inserted, because the structure of the collection is dependent upon the attributes of the object. For trees, any attributes used by the comparator cannot be changed once the item has been added. For maps, it's the hashCode that must remain constant.
So, in general, modify first, and then add. This becomes even more important with concurrent collections, since adding first can lead to other collection users seeing an object before it been assigned it's final state.
The example you provided won't have any issues because you're using a List collection which doesn't care about the Object contents.
If you were using something like TreeMap which internally sorts the contents of the Object keys it stores it could cause the Collection to get into an unexpected state. Again this depends on if the equals method uses the attribute you're changing to compare.
The safest way is to modify the object before placing it into the collection.
One of the good design rules to follow, is not to expose half-constructed object to a 3rd party subsystem.
So, according to this rule, initialize your object to the best of your abilities and then add it to the list.
If objects is an ArrayList then the net result is probably the same, however imaging if objects is a special flavor of List that fires some kind of notification event every time a new object is added to it, then the order will matter greatly.
In my opinion its depend of the settted attribure and tyle of collection, if the collection is a Set and the attribute have infulance on the method equal or hascode then definitely i will set this property before this refer also to sorterd list etc. in other cases this is irrelevant. But for this exapmle where object is created i will first set the atributes than add to collection because the code is better organized.
I think either way it's the same, personally I like B, :)
It really does boil down to what the situation requires. Functionally there's no difference.
One thing you should be careful with, is being sure you have the correct handle to the object you want to modify.
Certainly in this instance, modifying the object is part of the "create the object" thought, and so should be grouped with the constructor as such. After you "create the object" you "add it to the collection". Thus, I would do B, and maybe even add a blank line after the modification to give more emphasis on the two separate thoughts.