If I have a rarely used collection in some class which may be instantiated many times, I may sometimes resort to the following "idiom" in order to save unnecessary object creations:
List<Object> list = null;
void add(Object object) {
if (list == null)
list = new ArrayList<Object>();
list.add(object);
}
// somewhere else
if (list != null)
for (Object object : list)
;
Now I was wondering if I couldn't eliminate those null checks using Collections.emptyList(), however then I would have to alter the if check in add() like so:
if (list == Collections.<Object>emptyList())
list = new ArrayList<Object>();
Is there a better way to handle this other than just allocating a new empty collection every time?
EDIT: just to be clear, I would like to use Collections.emptyList(), but the above check in add() is really really ugly... I was wondering if there's a better way to do it or even a whole other way of handling this.
in order to save unnecessary object creations
That's a really bad idea which will litter your code with == null checks and other handling of corner cases (and presumably end up in null pointer exceptions anyway)!
Now I was wondering if I couldn't eliminate those null checks using Collections.emptyList()
No, not really. emptyList() returns an empty list. You could do
if (list.equals(Collections.<Object>emptyList()))
but that will still throw a NullPointerException if list == null, so it's still not what you're after.
My recommendation: Always initialize the list to new ArrayList<Object>, or, if you for instance want to return an empty list from a method, use Collections.emptyList() instead. (This returns the same instance every time, so no unnecessary object creation there either.)
And then use .isEmpty() to check if a collection is empty or not.
The suggested answers are absolutely correct, just small tip - in Java 8 you can use the new Optional class to handle the case where the list instance is null, in a more functional approach.
For example, something like this:
public static List<String> addElement(List<String> list, String toAdd) {
List<String> newList = Optional.ofNullable(list).orElse(new ArrayList<>());
newList.add(toAdd);
return newList;
}
Following a tip in the comments, it's better to replace new ArrayList<>() with Collections.emptyList() in order to prevent the creation of a new instance of an empty ArrayList
public static List<String> addElement(List<String> list, String toAdd) {
List<String> newList = Optional.ofNullable(list).orElse(Collections.emptyList());
newList.add(toAdd);
return newList;
}
There is an emptyIfNull method in package org.apache.commons.collections4;. It returns an empty list if the one provided is null.
List<Object> list = CollectionUtils.emptyIfNull(list);
Here is what I use for a helper method in some of my code. Really works nicely in reducing the ton of null checks I'd normally have to place before iterating over lists. If you want a list that wouldn't be immutable then you can return a new list object instead of Collections.emptyList
/**
* Helper method to return an empty list if provided one is null.
*
* #param list the list
* #return the provided list or an empty one if it was null
*/
private static <T> List<T> emptyIfNull(List<T> list) {
if (list == null) {
return Collections.emptyList();
}
return list;
}
You then just use the helper method like so:
for (Object object : emptyIfNull(existingList)) { ... }
If the list object is null, then the helper method will return the static empty list and the contents of your loop will be skipped. This is a nice way to avoid having to create null checks wrapping any list iterations.
I've made the internals of the list be of type Object just for the example, but you'd obviously change this to be whatever makes the most sense for your usage.
emptyList() doesn't allocate an object each time.
I would create less of the object which contains the List so you can create the list every time.
What you can do is
private List<Object> list = Collections.emptyList();
private List<Object> listForWrite() {
return list.isEmpty() ? list = new ArrayList<Object>() : list;
}
void add(Object object) {
listForWrite().add(object);
}
// avoid creating an Iterator every time.
for (int i = 0, size = list.size(); i < size; i++) {
;
}
Here's a variation on using optional as #Stas suggested, but also using the isEmpty immutable collection as originally requested in the question:
public static List<String> addElement(List<String> list, String toAdd) {
List<String> newList = Optional.ofNullable(list).orElse(Collections.emptyList());
newList.add(toAdd);
return newList;
}
This approach is also the closest thing I can find to the nice ability in Javascript to use an empty array if the collection is null.
For example:
// no need to indent everything inside a null check of myObjects
for (MyObj myObj : Optional.ofNullable(myObjects).orElse(Collections.emptyList())){
// do stuff with myObj
}
If you only use the list for iterations, you could just use: for (Object object : list) which wouldn't do anything for empty lists, i.e. not a single iteration.
Otherwise just check list.isEmpty().
You can create a utility class with static methods, like:
public class ListUtil {
/**
* Checks if {#link List} is null or empty.
*
* #param <E> the generic type
* #param list the list
* #return true, if is null or empty
*/
public static <E> boolean isNullOrEmpty(List<E> list) {
return list == null || list.size() == 0;
}
/**
* Checks if {#link List} is not null and empty.
*
* #param <E> the generic type
* #param list the list
* #return true, if is not null and empty
*/
public static <E> boolean isNotNullAndEmpty(List<E> list) {
return list != null && list.size() != 0;
}
}
I find it easiest to follow this convention:
If the point of my methods is to return a Collection, the method never returns null. Null is ambiguous. Instead I return Collection.emptyXXX() or ImmutableXXX.of() if using Guava.
If I have an object which is maintaining an internal list as a member, instantiate it in the constructor. I try not to do lazy instantiation unless I can prove its a significant gain because lazy code, in my opinion, tends to be more difficult to debug when issues arise.
I really see immutable or unmodifiable empty collections being a part of a contract external to objects. If you are using the collection internally, I can only really see using immutable collections if you have a good reason (concurrency, consistency, immutability of the object)
Related
I get is null using apache collections utils in java 8:
if (CollectionUtils.isNotEmpty(reportEnvelopeApps)) {
}
But if the collection reportEnvelopeApps contains one element null, It works unexpectedly. So I have to write code like this:
if (reportEnvelopeApps == null) {
return null;
}
reportEnvelopeApps.removeAll(Collections.singleton(null));
if (CollectionUtils.isEmpty(reportEnvelopeApps)) {
return null;
}
What is the better way to avoid bad code like this?
You can use Optional and return list with only non null elements or else return null
List<String> res = Optional.ofNullable(reportEnvelopeApps)
.map(list->list.removeIf(Objects::isNull) ? list : list)
.filter(list->!list.isEmpty())
.orElse(null);
You can simply wrap this in a utility method
public (static) List<String> removeNull(List<String> orig){
if(orig==null){
return Collections.emptyList();
}
return orig.stream.filter(x->x!=null).collect(Collectors.toList);
}
You can put that in your own CollectionUtil/ListUtil class or somewhere else where you can easily re-use it. Your main code then just applies the filter method and checks whether the list has any values. If at all necessary - at best you simply have code that iterates over the list, making special case handling for null/empty list obsolete.
If you really care for speed, you might just hand around streams instead of collections, that would avoid the copy that is being created here, but in most cases that is a non-issue.
You could collect all possible non-null elements to a new list, using Stream, after CollectionUtils.isNotEmpty(reportEnvelopeApps)
if (CollectionUtils.isNotEmpty(reportEnvelopeApps)) {
List<ReportEnvelope> nonNullList = reportEnvelopeApps
.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
// Proceed with whatever needs to be done with the new list.
}
I want to collect items based on a filter. But the resulting list should not be initialized if no match was found. I'd prefer null instead of empty list.
List<String> match = list
.stream()
.filter(item -> item.getProperty == "match")
.collect(Collectors.toList());
if (match != null && !match.isEmpty()) {
//handle seldom match
}
Problem: most of the time I will not have a match, resulting in an empty collection. Which means most of the time the list is instanciated even though I don't need it.
Collecto.toList() allocates a List using ArrayList::new which is a very cheap operation since ArrayList doesn't actually allocate the backing array until elements are inserted. All the constructor does is initialize an internal Object[] field to the value of a statically created empty array. The actual backing array is initialized to its "initial size" only when the first element is inserted.
So why go through the pain of avoiding this construction? It sounds like a premature optimization.
If you're so worried about GC pressure, just don't use Streams. The stream and the Collector itself are probably quite a lot more "expensive" to create than the list.
I am only thinking of a case when something other than Collectors.toList() would be expensive to compute, otherwise use:
... collect(Collectors.collectingAndThen(list -> {
list.isEmpty() ? null: list;
}))
But just keep in mind that someone using that List would most probably expect an empty one in case of missing elements, instead of a null.
Creating an empty ArrayList is quite cheap and laziness here would only make things worse.
Otherwise, here is a variant that could defer to null if you really really wanted to:
private static <T> List<T> list(Stream<T> stream) {
Spliterator<T> sp = stream.spliterator();
if (sp.getExactSizeIfKnown() == 0) {
System.out.println("Exact zero known");
return null;
}
T[] first = (T[]) new Object[1];
boolean b = sp.tryAdvance(x -> first[0] = x);
if (b) {
List<T> list = new ArrayList<>();
list.add(first[0]);
sp.forEachRemaining(list::add);
return list;
}
return null;
}
List<String> doSomething(String input){
if(input == null){
return Collections.emptyList();
}
List<String> lst = getListfromSomewhereElse(input)
if(lst.isEmpty(){
return Collections.emptyList(); //Approach 1
// return lst; //Return same empty list
}
// do some more processing on lst
return lst;
}
I prefer approach 1, coz its more readable and explicit. What is better approch 1 or 2?
Question is if the list is empty should i return same list or explicitly create new empty list and return
Collections.emptyList() return one constant member of Collections, so it takes no excessive time (can be optimized by JIT) and memory.
On the other side return of getListfromSomewhereElse possibly locks empty list returned from other code. Potentially you can get any list class and potentially it can take a bit of memory. Generally it's not a problem, as this method is also derived, reviewed and tested by your own team, but who knows what happens in outer libraries?
For example, getListfromSomewhereElse can read really large file into memory and then remove all elements from it. So, empty list will hold thousands elements capacity unless you/them know its structure and get rid of excessive capacity. Approach 1 will simply overcome this by usage of already existing constant list.
As a side note, if you process list elements in java 8 stream style, you naturally get new list with .collect(Collectors.toList()) step. But JDK developers don't force emptyList in this case.
So, unless you are sure in getListfromSomewhereElse, you better return Collections.emptyList() (or new ArrayList() or whatever list type you return by method contract).
I would prefer
List<String> doSomething(String input) {
List<String> list = new ArrayList<String>();
if (input != null) {
List<String> listFromSomewhereElse = getListfromSomewhereElse(input);
list.addAll(listFromSomewhereElse);
}
return list;
}
Keep in mind that Collections.emptyList() is unmodifiable. Depending on the result of getListFromSomewhereElse a client of doSomething might be confused that it can sometimes modify the list it gets and under some other situation it throws an UnsupportedOperationException. E.g.
List<String> list = someClass.doSomething(null);
list.add("A");
will throw UnsupportedOperationException
while
List<String> list = someClass.doSomething("B");
list.add("A");
might work depending on the result of getListFromSomewhereElse
It's very seldom necessary to do (pseudocode):
if(input list is empty) {
return an empty list
} else {
map each entry in input list to output list
}
... because every mainstream way of mapping an input list to an output list produces an empty list "automatically" for an empty input. For example:
List<String> input = Collections.emptyList();
List<String> output = new ArrayList<>();
for(String entry : input) {
output.add(entry.toLowerCase());
}
return output;
... will return an empty list. To treat an empty list as a special case makes for wasted code, and less expressive code.
Likewise, the modern Java approach of using Streams does the same:
List<String> output = input.stream()
.map( s -> s.toLowerCase())
.collect(Collectors.toList());
... will create an empty List in output, with no "special" handling for an empty input.
Collections.emptyList() returns a class that specifically implements an immutable, empty list. It has a very simple implementation, for example its size() is just return 0;.
But this means your caller won't be able to modify the returned list -- only if it's empty. Although immutability is a good thing, it's inconsistent to sometimes return a immutable list and other times not, and this could result in errors you detect late. If you want to enforce immutability, to it always by wrapping the response in Collections.unmodifiableList(), or using an immutable list from a library like Guava.
You also test whether the input is null. Consider whether this is necessary. Who's going to be calling the method? If it's just you, then don't do that! If you know you're not going to do it, your code needn't check for it.
If it's a public API for other programmers, you might need to handle nulls gratefully, but in many cases it's entirely appropriate to document that the input mustn't be null, and just let it throw a NullPointerException if it happens (or you can force one early by starting your method with Objects.requireNonNull(input).
Conclusion: my recommendation is:
List<String> doSomething(String input){
Objects.requireNonNull(input); // or omit this and let an
// exception happen further down
return doMoreProcessingOn(getListfromSomewhereElse(input));
}
It's best if doMoreProcessingOn() produces a new List, rather than modifying input.
while developing I was trying to return an empty List.
public Collection<?> getElements() {
// return elements
}
I searched for an easy way, my first idea was to create for example an ArrayList without any elements and return it. Like the following example:
public Collection<?> getElements() {
return new ArrayList<?>();
}
For me it is too much overhead for an empty list.
There is a really simple solution for the above described "problem":
public Collection<?> getElements() {
return Collections.EMPTY_LIST;
}
That returns an empty list.
Notice:
It returns an immutable object! You can use it only, if you need an object, which isn't editable.
Type-safety
In the case you want to get a type-safe list you should use the following example [1]:
List<String> s = Collections.emptyList();
Three kinds of interfaces are supported:
List:
List l = Collections.EMPTY_LIST;
List<String> s = Collections.emptyList();
Map:
Map m = Collections.EMPTY_MAP;
Map<String> ms = Collections.emptyMap();
Set:
Set s = Collections.EMPTY_SET;
Set<String> ss = Collections.emptySet();
Notice:
Implementations of this method need not create a separate XXX object
for each call. Using this method is likely to have comparable cost to
using the like-named field. (Unlike this method, the field does not
provide type safety.)
Given a list of objects (all of the same type), how can I make sure that it contains only one element for each value of a certain attribute, even though equals() may return false for such elements due to more attributes being checked? In code:
private void example() {
List<SomeType> listWithDuplicates = new ArrayList<SomeType>();
/*
* create the "duplicate" objects. Note that both attributes passed to
* the constructor are used in equals(), though for the purpose of this
* question they are considered equal if the first argument was equal
*/
SomeType someObject1 = new SomeObject1("hello", "1");
SomeType someObject2 = new SomeObject1("hello", "2");
List<SomeType> listWithoutDuplicates = removeDuplicates(listWithDuplicates)
//listWithoutDuplicates should not contain someObject2
}
private List<SomeType> removeDuplicates(List<SomeType> listWithDuplicates) {
/*
* remove all but the first entry in the list where the first constructor-
* arg was the same
*/
}
Could use a Set as an intermediary placeholder to find the duplicates as Bozho suggested. Here's a sample removeDuplicates() implementation.
private List<SomeType> removeDuplicates(List<SomeType> listWithDuplicates) {
/* Set of all attributes seen so far */
Set<AttributeType> attributes = new HashSet<AttributeType>();
/* All confirmed duplicates go in here */
List duplicates = new ArrayList<SomeType>();
for(SomeType x : listWithDuplicates) {
if(attributes.contains(x.firstAttribute())) {
duplicates.add(x);
}
attributes.add(x.firstAttribute());
}
/* Clean list without any dups */
return listWithDuplicates.removeAll(duplicates);
}
Maybe a HashMap can be used like this:
private List<SomeType> removeDuplicates(List<SomeType> listWithDuplicates) {
/*
* remove all but the first entry in the list where the first constructor-
* arg was the same
*/
Iterator<SomeType> iter = listWithDuplicates.iterator();
Map<String, SomeType> map = new HashMap<String, SomeType>();
while(iter.hasnext()){
SomeType i = iter.next();
if(!map.containsKey(i.getAttribute())){
map.put(i.getAttribute(), i);
}
}
//At this point the map.values() is a collection of objects that are not duplicates.
}
If equals() were suitable, I could recommend some "standard" Collections classes/methods. As it is, I think your only option will be to either
copy each element to another list after first checking all preceding elements in the original list for duplicates; or
delete from your list any element for which you've found a duplicate at a preceding location. For in-list deletion, you'd be best off with using a LinkedList, where deletion isn't so expensive.
In either case, checking for duplicates will be an O(n^2) operation, alas.
If you're going to be a lot of this kind of operation, it might be worthwhile to wrap your list elements inside another class that returns a hashcode based on your own defined criteria.
I'd look at implementing the Comparator interface for something like this. If there's a simple attribute or two that you wish to use for your comparison, that makes it pretty straightforward.
Related question: How Best to Compare Two Collections in Java and Act on Them?