I try to use stream to manage dto to bean.
List<CarDto> carsDto = dto.getCars();
List<Cars> cars = bean.getCars();
for (Cars car : cars) {
if (carsDto==null || carsDto.stream().noneMatch(c -> c.getId().intValue() == car.getId())) {
bean.removeCars(car);
}
}
actually when element of carsDto is null, i get null pointer exception.
when element is null, I would like to do
bean.removeCars(car);
A stacktrace or some code about the classes would be quite helpful. My bet is the NPE occurs in the line containing if and comes from a null being casted to a primitive int in one of these two:
c.getId() // returns null or
car.getId() // returns null
If the NPE doesn't come from one of these, then dto.getCars() might return a List with null values or bean.removeCars(car) throws an NPE...
Neither Stream.allMatch, .noneMatch, anyMatch nor any reduction function that reduces to a single boolean can do the trick alone because while you want to remove the car when no dto matches the car, you want to remove it when any dto is null.
You could always use two stream pipelines if you don't mind having twice as bad performances, but I will instead suggest the following :
List<CarDto> carsDto = dto.getCars();
List<Cars> cars = bean.getCars();
if (carsDto == null || carsDto.stream().anyMatch(Objects::isNull)) {
cars.forEach(car -> bean.removeCars(car)); //remove all cars when the dto list is null or contains a null dto
} else {
cars.stream().filter(car -> //select cars with a corresponding dto
carsDto.stream().anyMatch(dto ->
car.getId() == dto.getId().intValue()
)
).forEach(car -> bean.removeCars(car)); //and remove them
}
Related
I want to simplify my code without using too many If-Else condition.
The business logic I want is:
I retrieved data of customer's account from DB
I want to check whether each customer is qualified for applying new product
If She/He has the account, then passed
Otherwise failed.
Repository
public interface MyRepository extends JpaRepository<Account, String>{
Optional<List<Account>> findAcctByCustoNo(String custNo);
}
The logic code
Optional<List<Account>> accounts = myRepo.findAcctByCustoNo(auth.getCustNo());
if(!accounts.isPresent()) {
return "invalid param";
}
accounts.ifPresent(list->list.stream()
.filter(type -> type.getAccCd().equals("typeA") || type.getAccCd().equals("typeB"))
.forEach(System.out::println));
The code hasn't finished yet. I need to check, after filtering the data, if it still return null value, I want to return "No Data" message, something like this. Or apply another method or else.
And I don't know how to do it properly. Because What I can think is add create new instance after filtering, and check it with isPresent again. But I have a feeling that I can do it inside the accounts instance.
Please enlighten me.
I just use this Optional feature recently. I spent a lot of time understanding the method inside it. I was thinking to utilize map, but again, I have no idea how to implement it in the right way.
What about this ?
Do all the filtering you want, then use findAny (cheaper than count() since it will stop as soon as it has a match) and check the result
Optional<List<Account>> accounts = myRepo.findAcctByCustoNo(auth.getCustNo());
return accounts //
.map(List::stream) //
.orElseGet(Stream::empty) //
.filter(type -> type.getAccCd().equals("typeA") || type.getAccCd().equals("typeB")) //
.findAny() //
.orElse(null)
!= null;
Explanation
map your optional List to a stream
if not, use an empty stream
then, filter all you want
findAny ? we are good.
orElse, return null
And finally, check for null.
Test code on simpler data :
#Test
public void test_checkArray() {
Assert.assertFalse(this.checkArray(null));
Assert.assertFalse(this.checkArray(Arrays.asList()));
Assert.assertFalse(this.checkArray(Arrays.asList("not a!", "b", "c")));
Assert.assertTrue(this.checkArray(Arrays.asList("a", "b", "c")));
}
private boolean checkArray(final List<String> a) {
return Optional //
.ofNullable(a) //
.map(List::stream) //
.orElseGet(Stream::empty) //
.filter(aa -> "a".equals(aa)) //
.findAny() //
.orElse(null)
!= null;
}
Not sure how you intend to use the info after, but if you just need to see if the customer qualifies, you can try
boolean qualify = accounts.stream()
.filter(type -> type.getAccCd().equals("typeA") || type.getAccCd().equals("typeB"))
.findFirst()
.isPresent();
This will return true if the customer qualifies, otherwise false.
You can rearrange code like this
Optional.of(myRepo.findAcctByCustoNo(auth.getCustNo()))
.filter(.....)
.orElse(......);
Optional methods return Optional object, thus it allows method chaining.
How can i rewrite this:
private Comparator<Domain> byRank;
...
byRank = new Comparator<Domain>() {
#Override
public int compare(Domain d1, Domain d2) {
float tmp1 = d1.getDomainRank() == null ? 0 : d1.getDomainRank();
float tmp2 = d2.getDomainRank() == null ? 0 : d2.getDomainRank();
return Float.compare(tmp1, tmp2);
}
};
into lambda?
According to check null value before sorting using lambda expression, I tried this:
byRank = Comparator.nullsFirst(Comparator.comparing(Domain::getDomainRank));
However, it fails with:
java.lang.NullPointerException: null
at java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469)
at java.util.Comparators$NullComparator.compare(Comparators.java:83)
at java.util.PriorityQueue.siftUpUsingComparator(PriorityQueue.java:669)
at java.util.PriorityQueue.siftUp(PriorityQueue.java:645)
at java.util.PriorityQueue.offer(PriorityQueue.java:344)
at java.util.PriorityQueue.add(PriorityQueue.java:321)
Edit: the lambda fails even if I check compared objects for null before comparison:
Queue<Domain> topByRank = new PriorityQueue<>(TOP, byRank);
...
for (Domain domain : domains) {
if (domain == null) { // check here
continue;
}
topByRank.add(domain); // here it fails
}
It should be:
Comparator.comparing(Domain::getDomainRank,
Comparator.nullsFirst(Comparator.naturalOrder()))
So we sort a list based on domainRank. But what are we going to do with Domain objects whose domainRank value is null? We going to keep them at the head of our collection:
Comparator.nullsFirst(Comparator.naturalOrder())
Your code will put null Domains first. If you want to check for null rank, you need to use this:
Comparator.comparing(Domain::getDomainRank, Comparator.nullsFirst(Comparator.naturalOrder()))
But keep in mind that this is only equivalent to your original comparator if the rank can't be less than 0. Otherwise, you'll have to test a similar expression:
Comparator.comparing(d -> d.getDomainRank() == null ? 0 : d.getDomainRank())
Alternatively, you might have meant to use Float.MIN_VALUE instead of 0 in your original code.
Working with hibernate I use this sort of code many times:
int someId = entity.getSomething() == null ? null : entity.getSomething().getId();
This code becomes a little more messy when trying to apply on a longer hierarchy:
int someId = entity.getParent() == null ? null :
entity.getParent().getParent() == null ? null :
entity.getParent().getParent().getSomething() == null ? null :
entity.getParent().getParent().getSomething().getId();
Is there a more elegant way to do it?
As per Louis Wasserman's comment, Optional can almost be used as a NullObject a'la flogy's solution.
Using Java 8 Optional and lambdas it looks like this
Integer value = Optional.ofNullable(entity)
.map( Entity::getParent )
.map( Entity::getParent )
.map( Entity::getSomething )
.map( Something::getId )
.orElse(null);
In case those entity objects are written by yourself and not in a library, I would consider refactoring them and use NullObjects. Like that you could then directly call
Integer someId = entity.getParent().getParent().getSomething().getId();
as this would then return your nulled integer.
Basically, it works like this:
entity.getParent() will return a NullParent instance
this NullParent class has a method getParent(), which also will return a NullParent instance
again, this NullParent class has a method getSomething(), which will return a NullSomething instance
the NullSomething class has a method getId(), which finally will return your nulled integer (e.g. 0 or another NullInteger object).
Here is an interesting post on Why NULL is bad?
Is there a more elegant way to do it?
You may simply go for try-catch for null check:
try{
int id = entity.getParent().getParent().getSomething().getId();
// do something with id
} catch(NullPointerException ex) {
// got null
}
You're assigning the same null value if it's null.
Why don't you try giving it only if it is not null.
if(x != null) x = y
Readability is very important factor as well as the simplification of code. It is better to use simple if condition here.
if(entity.getParent()!=null && entity.getParent().getParent() !=null &&
entity.getParent().getParent().getSomething()!=null &&
entity.getParent().getParent().getSomething().getId()!=null){
}
And because of &&("short-circuit and"), if one condition false non other condition in the right execute.
I trying to replace existing loop with java lambda expresions.
I have simple data structure that looks like follow:
class DbObject{
private Long objectId;
private Long basedOnObjectId; //<- this field can be null
public Long getObjectId() {
return objectId;
}
public void setObjectId(Long objectId) {
this.objectId = objectId;
}
public Long getBasedOnObjectId() {
return basedOnObjectId;
}
public void setBasedOnObjectId(Long basedOnObjectId) {
this.basedOnObjectId = basedOnObjectId;
}
}
Then I have a List of DbObjects
And I trying to filter each DbObject with specified basedOnObjectId:
(1) list.stream().filter(object -> obejct.getBasedOnObjectId()
.equals(basedOnObject.getObjectId()))
.collect(Collector.of(List))
Of course this code gives me NullPointer because some od DbObject didn't have BasedOnObjectId because they are roots.
So natural thing is to replace field "Long basedOnObjectId;" by Optional but as I mentioned at start there are existing production code co it isn't fast fix.
So I trying to make some changes, I evaluate following sentence:
Optional<Long> option = Optional.ofNullable(objectWithNullBasedOnId.getBasedOnObjectId());
And Try with .get() method or .ifPresent() but .get() also throw null pointer exception and ifPresent is not dedicated to work with stream.
I noticed that and the fact that When I have DbObject with null basedOnObjectId I don't have to check if value is exactly null but only skip this step of execution.
So I decided to use .orElse() method and return some fake value. In this case i return 0L value because this index don't exist in DB :)
So my code :
(2) List newList = list.stream().filter(object -> Optional.ofNullable(object.getBasedOnObjectId())
.orElse(0L)
.equals(basedOnObject.getObjectId()) )
.collect(Collectors.toList()) ;
And this work correctly in this case, but I think this is some kind of workaround. In other languages are possible to skip execution with null value, or use some like skip-skipWhen methods.
My question is : if exist possibility to reach the goal of (2) expression using dedicated method (in example Optional) from java 8 and write "in stream style" :)
You don't need to introduce Optional here. You just need to be aware that null is in your domain, and deal accordingly. Like this:
list.stream().filter(o -> Objects.equals(o.getBasedOnObjectId(),
basedOnObject.getObjectId()))
.collect(toList());
or by filtering out the nulls explicitly (.filter(o -> o.getBasedOnObjectId() != null) or by rolling a null check into your existing filter condition.
No reason to make this more complicated than it needs to be. Objects.equals() is likely what you want, just use that.
If you compare Optional<Long> instead of Long, there is no need for a distinction between present and absent objects.
Optional<Long> root = Optional.of(basedOnObject.getObjectId());
list.stream()
.map(DbObject::getBasedOnObjectId)
.map(Optional::ofNullable)
.filter(root::equals)
.collect(Collectors.toList());
In this case, it is even simpler, because you can just reverse the comparison:
list.stream()
.filter(o -> basedOnObject.getObjectId().equals(o.getBasedOnObjectId()))
.collect(Collectors.toList());
You probably want to actually remove the null objects from the stream before passing them to subsequent operations. Try mapping the objects to the BasedOnObjectId form and then filtering the null values:
list.stream()
.map(object -> object.getBasedOnObjectId())
.filter(object -> object != null)
...
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 :)