Any null safe alternative to ArrayList.addAll? - java

I was refactoring some old code of mine that I've written and I stumbeled on this code:
List<OcmImageData> fullImagePool = new ArrayList<>();
if (CollectionUtils.isNotEmpty(style.getTestMH())) {
fullImagePool.addAll(style.getTestMH());
}
if (CollectionUtils.isNotEmpty(style.getTrousers())) {
fullImagePool.addAll(style.getTrousers());
}
if (CollectionUtils.isNotEmpty(style.getDetailRevers())) {
fullImagePool.addAll(style.getDetailRevers());
}
if (CollectionUtils.isNotEmpty(style.getDetailCuffs())) {
fullImagePool.addAll(style.getDetailCuffs());
}
if (CollectionUtils.isNotEmpty(style.getDetailInner())) {
fullImagePool.addAll(style.getDetailInner());
}
if (CollectionUtils.isNotEmpty(style.getDetailMaterial())) {
fullImagePool.addAll(style.getDetailMaterial());
}
if (CollectionUtils.isNotEmpty(style.getComposing())) {
fullImagePool.addAll(style.getComposing());
}
...
So basically I need to create an ArrayList which contains all Lists here referenced, because those can be null (they are fetched out of the database from an closed sourced framework, and unfortunately its null if he doesn't find anything), I need to check everytime if the collection is not null to add them into this pool which looks just weird.
Is there a library or Collection-Framework utility class that gives me the posibility to add a collection to another without performing the null-safe check?

In Java 8 Use below code:-
Optional.ofNullable(listToBeAdded).ifPresent(listToBeAddedTo::addAll)
listToBeAdded - The list whose elements are to be added.
listToBeAddedTo - The list to which you are adding elements using addAll.

Just write a small utility method:
public static <E> void addAllIfNotNull(List<E> list, Collection<? extends E> c) {
if (c != null) {
list.addAll(c);
}
}
so that you can write:
List<OcmImageData> fullImagePool = new ArrayList<>();
addAllIfNotNull(fullImagePool, style.getTestMH());
addAllIfNotNull(fullImagePool, style.getTrousers());
addAllIfNotNull(fullImagePool, style.getDetailRevers());
// ...etc

Using Java 8:
List<OcmImageData> fullImagePool = Stream.of(style.getTestMH(), /* etc */)
.filter(Objects::nonNull)
.flatMap(l -> l.stream())
.collect(Collectors.toList());

This refactors cleanly to
for (OcmImageData elem : new List<OcmImageData>[] { style.getTestMH(), style.getTrousers() /* etc */}) {
if (CollectionUtils.isNotEmpty(elem)) {
fullImagePull.addAll(elem);
}
}
To answer your original question, no, you will have to do your own null check. You can see Guava's methods will throw an NPE, and Apache's methods explicitly require the input to be not null.

Related

Refactoring Java For loop code to use Java 8 streams API

I have following method which is used for creating a order in the database, order has many items and, item has many bills. iPadPOSOrderDTO is the order which is going to base saved into the database.
so, the loop based code for creating order is the following
private void createNewOrder(IPadPOSOrderDTO iPadPOSOrderDTO) {
IPadPOSOrderV2 order = mapper.map(iPadPOSOrderDTO, IPadPOSOrderV2.class);
if(order.getOrderV2Bills()!=null && order.getOrderV2Bills().size()>0){
for(IPadPOSOrderV2Bill orderBill : order.getOrderV2Bills()){
orderBill.setOrder(order);
if(orderBill.getiPadPOSOrderV2BillItems()!=null && orderBill.getiPadPOSOrderV2BillItems().size()>0){
for(IPadPOSOrderV2BillItems orderBillItem : orderBill.getiPadPOSOrderV2BillItems()){
orderBillItem.setiPadPOSOrderV2Bill(orderBill);
orderBillItem.setOrderId(order.getOrderId());
}
}
}
}
sessionFactory.
getCurrentSession().save(order);
}
I wanted to refactor above code to use Java 8 streams API.
So, I did the following
private void createNewOrderV2(IPadPOSOrderDTO iPadPOSOrderDTO) {
IPadPOSOrderV2 order = mapper.map(iPadPOSOrderDTO, IPadPOSOrderV2.class);
if(order.getOrderV2Bills()!=null && order.getOrderV2Bills().size()>0){
order.getOrderV2Bills().stream().forEach(e -> { createBill(order,e);});
}
sessionFactory.
getCurrentSession().save(order);
}
private void createBill(IPadPOSOrderV2 ipadExistingOrderFromDatabase, IPadPOSOrderV2Bill iPadPOSOrderV2Bill) {
iPadPOSOrderV2Bill.setOrder(ipadExistingOrderFromDatabase);
if(iPadPOSOrderV2Bill.getiPadPOSOrderV2BillItems()!=null && iPadPOSOrderV2Bill.getiPadPOSOrderV2BillItems().size()>0){
iPadPOSOrderV2Bill.getiPadPOSOrderV2BillItems().stream().forEach(e -> createBillItem(ipadExistingOrderFromDatabase,iPadPOSOrderV2Bill,e));
}
}
private void createBillItem(IPadPOSOrderV2 ipadExistingOrderFromDatabase, IPadPOSOrderV2Bill iPadPOSOrderV2Bill, IPadPOSOrderV2BillItems iPadPOSOrderV2BillItem) {
iPadPOSOrderV2BillItem.setiPadPOSOrderV2Bill(iPadPOSOrderV2Bill);
iPadPOSOrderV2BillItem.setOrderId(ipadExistingOrderFromDatabase.getOrderId());
ipadExistingOrderFromDatabase.getOrderV2Bills().stream().forEach(e -> { createBill(ipadExistingOrderFromDatabase,e);});
}
could somebody share their experience and advice me if I am making the correct use of streams API for this refactoring.
Note that those size checks aren't really necessary. An empty list would result in an empty stream and thus nothing would get applied. The only benefit would be that you'd be able to avoid having to create the stream altogether but I highly doubt the performance difference would even be noticeble.
If you want to convert a potentially null collection to a stream you might want to use a small helper function:
public <T> Stream<T> collectionToStream(Collection<T> collection) {
return Optional.ofNullable(collection).map(Collection::stream).orElseGet(Stream::empty);
}
Using forEach() you could then do something like this:
private void createNewOrder(IPadPOSOrderDTO iPadPOSOrderDTO) {
IPadPOSOrderV2 order = mapper.map(iPadPOSOrderDTO, IPadPOSOrderV2.class);
collectionToStream(order.getOrderV2Bills()).forEach( orderBill -> {
orderBill.setOrder(order);
collectionToStream(orderBill.getiPadPOSOrderV2BillItems()).forEach(orderBillItem -> {
orderBillItem.setiPadPOSOrderV2Bill(orderBill);
orderBillItem.setOrderId(order.getOrderId());
}
}
}
}
sessionFactory.getCurrentSession().save(order);
}
Note that this isn't that different from your initial code and thus you should think about whether that conversion would make sense.
Converting your nested loops to a fully sequential stream would be harder and in the end not that different because you can't just flat map orderBill to a stream of orderBillItem. Doing that would not make orderBill available downstream so you'd have to call orderBillItem.setiPadPOSOrderV2Bill(orderBill); before returning the nested stream. That would end up in code very similar to the above and add no benefit because you're not using the returned stream.
Filter out the nulls ommiting the null checks
private void createNewOrderV2(IPadPOSOrderDTO iPadPOSOrderDTO) {
IPadPOSOrderV2 order = mapper.map(iPadPOSOrderDTO, IPadPOSOrderV2.class);
order.getOrderV2Bills().stream().filter(Objects::nonNull).forEach(e -> createBill(order, e));
sessionFactory.getCurrentSession().save(order);
}
private void createBill(IPadPOSOrderV2 ipadExistingOrderFromDatabase, IPadPOSOrderV2Bill iPadPOSOrderV2Bill) {
iPadPOSOrderV2Bill.setOrder(ipadExistingOrderFromDatabase);
iPadPOSOrderV2Bill.getiPadPOSOrderV2BillItems().stream().filter(Objects::nonNull).forEach(e -> {
e.setiPadPOSOrderV2Bill(iPadPOSOrderV2Bill);
e.setOrderId(ipadExistingOrderFromDatabase.getOrderId());
});
}
By the way your createBill() is called by the createBillItem and also the other way around, is this correct?

Return a list from list.forEach with Java Streaming API

I have a POJO:
class MyObject {
private Double a;
private String b;
//constructor, getter + setter
}
Some function is creating a list of this POJO. Some values for a might be null, so I want to replace them with 0.0. At the moment I am doing it like this.
public List<MyObject> fetchMyObjects(Predicate predicate) {
List<MyObject> list = getMyListsOfTheDatabase(predicate);
list
.forEach(myObject -> {
if (myObject.getA() == null) {
myObject.setA(0.0);
}
});
return list;
}
Is there a way to integrate the forEach in the return? Something like
return list
.stream()
.someStatement();
It's not about, if this is the best place to convert the nulls to zero, but rather a questions to better understand the streaming api.
Use the peek function
Returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.
public List<MyObject> fetchMyObjects(Predicate predicate) {
return getMyListsOfTheDatabase(predicate)
.stream()
.peek(it -> if(it.getA() == null) it.setA(0.0))
.collect(Collectors.toList());
}
While others have been happy to answer your question as it stands, allow me to step a step back and give you the answer you didn’t ask for (but maybe the answer that you want): You don’t want to do that. A stream operation should be free from side effects. What you are asking for is exactly a stream operation that has the side effect of modifying the original objects going into the stream. Such is poor code style and likely to confuse those reading your code after you.
The code you already have solves your problem much more nicely than any combined stream pipeline.
What you may want to have if you can modify your POJO is either a constructor that sets a to 0 if null was retrieved from the database, or method that does it that you may call from list.forEach:
list.forEach(MyObject::setAToZeroIfNull);
It's not about, if this is the best place to convert the nulls to
zero, but rather a questions to better understand the streaming api.
That’s fair. In any case I will let this answer stand for anyone else popping by.
You can't return the same List instance with a single statement, but you can return a new List instance containing the same (possibly modified) elements:
return list.stream()
.map(myObject -> {
if (myObject.getA() == null) {
myObject.setA(0.0);
}
return myObject;
})
.collect(Collectors.toList());
Actually you should be using List::replaceAll:
list.replaceAll(x -> {
if(x.getA() == null) x.setA(0.0D);
return x;
})
forEach doesn't have a return value, so what you might be looking for is map
return list
.stream()
.map(e -> {
if (e.getA() == null) e.setA(0d);
return e;
})
.whateverElse()...
The following would be fine:
list.stream()
.filter(obj -> obj.getA() == null)
.forEach(obj -> obj.setA(0.0));
return list;
However in your case just returning a Stream might be more appropriate (depends):
public Stream<MyObject> fetchMyObjects(Predicate predicate) {
return getMyListsOfTheDatabase(predicate);
}
public Stream<MyObject> streamMyObjects(List<MyObject> list) {
return list.stream()
.peek(obj -> {
if (obj.getA() == null) {
obj.setA(0.0);
}
});
}
I personally never used peek, but here it corrects values.
On code conventions, which are more string in the java community:
Indentation: Java took 4 as opposed to C++'s 3 as more separate methods,
and less indentation was expected. Debatable but okay.
For generic type parameters often a single capital like T, C, S.
For lambda parameters short names, often a single letter, hence I used obj.

Find and modify specific element in ArrayList

is some elegant way to find and modify some specific object in java? I have method like that:
public update(MyObj o) {
for (MyObj objToModify: DATA) {
if (objToModify.getId() == o.getId()) {
objToModify.setName(o.getName());
// and so on ...
}
}
}
Is possible to rewrite to lambda for example, or some other feature of Java 8? I had a lot of properties so I will prefer some option where I couldn't write manually set up all of new properties.
You can do it in the following way, this will go over the whole stream and update elements even if there is more then one matching:
DATA.stream().filter(a -> a.getId() == o.getId()).forEach(a -> a.setName(o.getName()));
Or if you are sure that you only need to update one element:
DATA.stream().filter(a -> a.getId() == o.getId()).
findAny().ifPresent(a -> a.setName(o.getName()));
Both solutions will throw NullPointerException if DATA has null elements the same as your original solution, if it's a posiibility and you want to prevent it you need to also check that a is not null in filter.
You can use lambda expression to do what you are trying to do
public update(MyObj o) {
DATA.forEach(objToModify -> {
if (objToModify.getId() == o.getId()) {
objToModify.setName(o.getName());
// and so on ...
}
});
}
although i am not sure if using lambda expression in your case will be more efficient than using for-each loop.

Null check in an enhanced for loop

What is the best way to guard against null in a for loop in Java?
This seems ugly :
if (someList != null) {
for (Object object : someList) {
// do whatever
}
}
Or
if (someList == null) {
return; // Or throw ex
}
for (Object object : someList) {
// do whatever
}
There might not be any other way. Should they have put it in the for construct itself, if it is null then don't run the loop?
You should better verify where you get that list from.
An empty list is all you need, because an empty list won't fail.
If you get this list from somewhere else and don't know if it is ok or not you could create a utility method and use it like this:
for( Object o : safe( list ) ) {
// do whatever
}
And of course safe would be:
public static List safe( List other ) {
return other == null ? Collections.EMPTY_LIST : other;
}
You could potentially write a helper method which returned an empty sequence if you passed in null:
public static <T> Iterable<T> emptyIfNull(Iterable<T> iterable) {
return iterable == null ? Collections.<T>emptyList() : iterable;
}
Then use:
for (Object object : emptyIfNull(someList)) {
}
I don't think I'd actually do that though - I'd usually use your second form. In particular, the "or throw ex" is important - if it really shouldn't be null, you should definitely throw an exception. You know that something has gone wrong, but you don't know the extent of the damage. Abort early.
It's already 2017, and you can now use Apache Commons Collections4
The usage:
for(Object obj : ListUtils.emptyIfNull(list1)){
// Do your stuff
}
You can do the same null-safe check to other Collection classes with CollectionUtils.emptyIfNull.
With Java 8 Optional:
for (Object object : Optional.ofNullable(someList).orElse(Collections.emptyList())) {
// do whatever
}
Use ArrayUtils.nullToEmpty from the commons-lang library for Arrays
for( Object o : ArrayUtils.nullToEmpty(list) ) {
// do whatever
}
This functionality exists in the commons-lang library, which is included in most Java projects.
// ArrayUtils.nullToEmpty source code
public static Object[] nullToEmpty(final Object[] array) {
if (isEmpty(array)) {
return EMPTY_OBJECT_ARRAY;
}
return array;
}
// ArrayUtils.isEmpty source code
public static boolean isEmpty(final Object[] array) {
return array == null || array.length == 0;
}
This is the same as the answer given by #OscarRyz, but for the sake of the DRY mantra, I believe it is worth noting. See the commons-lang project page. Here is the nullToEmpty API documentation and source
Maven entry to include commons-lang in your project if it is not already.
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
Unfortunately, commons-lang doesn't provide this functionality for List types. In this case you would have to use a helper method as previously mentioned.
public static <E> List<E> nullToEmpty(List<E> list)
{
if(list == null || list.isEmpty())
{
return Collections.emptyList();
}
return list;
}
If you are getting that List from a method call that you implement, then don't return null, return an empty List.
If you can't change the implementation then you are stuck with the null check. If it should't be null, then throw an exception.
I would not go for the helper method that returns an empty list because it may be useful some times but then you would get used to call it in every loop you make possibly hiding some bugs.
I have modified the above answer, so you don't need to cast from Object
public static <T> List<T> safeClient( List<T> other ) {
return other == null ? Collections.EMPTY_LIST : other;
}
and then simply call the List by
for (MyOwnObject ownObject : safeClient(someList)) {
// do whatever
}
Explaination:
MyOwnObject: If List<Integer> then MyOwnObject will be Integer in this case.
For anyone uninterested in writing their own static null safety method you can use: commons-lang's org.apache.commons.lang.ObjectUtils.defaultIfNull(Object, Object). For example:
for (final String item :
(List<String>)ObjectUtils.defaultIfNull(items, Collections.emptyList())) { ... }
ObjectUtils.defaultIfNull JavaDoc
Another way to effectively guard against a null in a for loop is to wrap your collection with Google Guava's Optional<T> as this, one hopes, makes the possibility of an effectively empty collection clear since the client would be expected to check if the collection is present with Optional.isPresent().
Use, CollectionUtils.isEmpty(Collection coll) method which is Null-safe check if the specified collection is empty.
for this import org.apache.commons.collections.CollectionUtils.
Maven dependency
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
for (Object object : someList) {
// do whatever
} throws the null pointer exception.

Google Collections Suppliers and Find

I'm looking for a Google Collections method that returns the first result of a sequence of Suppliers that doesn't return null.
I was looking at using Iterables.find() but in my Predicate I would have to call my supplier to compare the result against null, and then have to call it again once the find method returned the supplier.
Given your comment to Calm Storm's answer (the desire not to call Supplier.get() twice), then what about:
private static final Function<Supplier<X>, X> SUPPLY = new Function<....>() {
public X apply(Supplier<X> in) {
// If you will never have a null Supplier, you can skip the test;
// otherwise, null Supplier will be treated same as one that returns null
// from get(), i.e. skipped
return (in == null) ? null : in.get();
}
}
then
Iterable<Supplier<X>> suppliers = ... wherever this comes from ...
Iterable<X> supplied = Iterables.transform(suppliers, SUPPLY);
X first = Iterables.find(supplied, Predicates.notNull());
note that the Iterable that comes out of Iterables.transform() is lazily-evaluated, therefore as Iterables.find() loops over it, you only evaluate as far as the first non-null-returning one, and that only once.
You asked for how to do this using Google Collections, but here's how you would do it without using Google Collections. Compare it to Cowan's answer (which is a good answer) -- which is easier to understand?
private static Thing findThing(List<Supplier<Thing>> thingSuppliers) {
for (Supplier<Thing> supplier : thingSuppliers) {
Thing thing = supplier.get();
if (thing != null) {
return thing;
}
}
// throw exception or return null
}
In place of the comment -- if this was the fault of the caller of your class, throw IllegalArgumentException or IllegalStateException as appropriate; if this shouldn't have ever happened, use AssertionError; if it's a normal occurrence your code that invokes this expects to have to check for, you might return null.
What is wrong with this?
List<Supplier> supplierList = //somehow get the list
Supplier s = Iterables.find(supplierList, new Predicate<Supplier>(){
boolean apply(Supplier supplier) {
return supplier.isSomeMethodCall() == null;
}
boolean equals(Object o) {
return false;
}
});
Are you trying to save some lines? The only optimisation I can think is to static import the find so you can get rid of "Iterables". Also the predicate is an anonymous inner class, if you need it in more than one place you can create a class and it would look as,
List<Supplier> supplierList = //somehow get the list
Supplier s = find(supplierList, new SupplierPredicateFinder());
Where SupplierPredicateFinder is another class.
UPDATE : In that case find is the wrong method. You actually need a custom function like this which can return two values. If you are using commons-collections then you can use a DefaultMapEntry or you can simply return an Object[2] or a Map.Entry.
public static DefaultMapEntry getSupplier(List<Supplier> list) {
for(Supplier s : list) {
Object heavyObject = s.invokeCostlyMethod();
if(heavyObject != null) {
return new DefaultMapEntry(s, heavyObject);
}
}
}
Replace the DefaultMapEntry with a List of size 2 or a hashmap of size 1 or an array of length 2 :)

Categories

Resources