Adding a log when encounter null object in parallel stream - java

Not sure about the syntax here, new to lambda expressions and the sort.
itemStream.parallel().filter(Objects::nonNull).forEach(
(item) -> randomMethod(item));
What I had previously in a for loop was a check for null and then a warning if encountered a null item
log.warn("Skipping a null item!");
How do I log when it encounters a null object (while still filtering) with the stream based approach?

You can use Stream::peek:
itemStream.parallel()
.peek(item -> { if (item == null) log.warn("Skipping a null item!"); })
.filter(Objects::nonNull)
.forEach(item -> randomMethod(item));
You can also use a method reference for randomMethod (here I assume it's a member of this):
itemStream.parallel()
.peek(item -> { if (item == null) log.warn("Skipping a null item!"); })
.filter(Objects::nonNull)
.forEach(this::randomMethod);

After filtering null items you can't find them!
Simply use this:
itemStream.parallel().forEach((item)-> {
if(item==null)
log.warn("Skipping a null item!");
else
randomMethod(item)
});

With .filter(Objects::nonNull) you're filtering out all the null elements and only retaining the non-null elements which means in the forEach you won't receive any null elements never mind logging it. instead, you want:
itemStream.parallel()
.forEach(item -> {
if(Objects.isNull(item)) { ... } else { ... }; // or if(item == null) ...
});

Related

Java 8 stream flatMap allow null check for each list in the nested list?

I have a nested list to loop through in pre Java 8. My example is very similar to loop through nested list in java 8 which is a great example to follow then I realized that I need to check for null for each list. Plz refer to the below example. If the last condition is met then return true by short-circuiting.
However I am not sure how to check null for each list using list.stream().flatMap().
for(A a : ListA) {
if(a.getListB() != null && !a.getListB().isEmpty()) {
for(B b : a.getListB()) {
if(b.getListC() != null && !p.getListC().isEmpty()) {
for(C c : b.getListC()) {
return (c.name.equalsIgnoreCase("john"));
}
}
}
}
}
This is kind of gross but it works. You essentially check if listB is not null and create a Stream of B. Then filter through Stream of B and check if ListC is null and if not map to a Stream of C. Then just simply check if any of C match the argument.
boolean found = listA.stream()
.filter(a -> a.getListB() != null)
.flatMap(a -> a.getListB().stream())
.filter(b -> b.getListC() != null)
.flatMap(b -> b.getListC().stream())
.anyMatch(c -> c.name.equalsIgnoreCase("john"));

Java 8 Optional detect empty collection

Using Java Optional:
List<String> myList = ....
Optional.ofNullable(myList)
.ifPresentOrElse(.. do something.., ()-> log.error("missing list"));
I do want to catch in logs when the list is null or empty. The above works perfectly for null. How can it be extended to catch the empty collections?
I think going with if()else{} is more readable. You can do like this:
Optional.ofNullable(myList == null || myList.isEmpty() ? null: myList)
.ifPresentOrElse(.. do something.., ()-> log.error("missing list"));
if you really want to complicate things using Optional -
Optional.ofNullable(myList).filter(l -> !l.isEmpty())
.ifPresentOrElse(.. do something.., ()-> log.error("missing list"));
better would be using the if-else -
if(myList !=null && !myList.isEmpty()) {
// do something
} else {
log.error("missing list");
}
further improvement - ensure that the List is not assigned a null value.

Finding string in optional list of lists

I have a list of 'Blocks' that could be null. Each of the blocks contains a list of names that also could be null. I'm trying to find if any of the names in all the blocks is the word "blurb".
I have the following code which does work:
private boolean containsText(List<Blocks> blocks) {
return Optional.ofNullable(blocks)
.map(Collection::stream)
.map(o -> o.map(Blocks::getNames))
.map(e -> e.anyMatch(names -> names != null && names.contains("blurb")))
.orElse(false);
}
But since getNames could return null I have to check for it in the next statement. I could wrap it in another Optional at that point, but then I would end up with an
Optional<Stream<Optional<List<String>>>>
Using names -> names != null
seems cleaner? Or is there a way to simplify this?
With Java-9 you can use Stream.ofNullable as follows:
public boolean containsText(List<Blocks> blocks) {
return Stream.ofNullable(blocks)
.flatMap(b -> b.stream().map(Blocks::getNames).filter(Objects::nonNull))
.anyMatch(s -> s.contains("blurb"));
}
Another simpler variant without the use of Optional would just be :
private boolean containsText(List<Blocks> blocks) {
return blocks != null && blocks.stream()
.map(Blocks::getNames)
.filter(Objects::nonNull)
.anyMatch(list -> list.contains("blurb"));
}
Note: One of your problems is the design where you say, "I have a list of 'Blocks' that could be null", you should fix it to return an empty list for such representation and then get rid of the null check in the above code.
I would not recommend using Optional for null check you can use ternary operator to check blocks is null and simply return false if it is null, else stream the blocks list and check for string
return Objects.isNull(blocks) ? false : blocks.stream()
.map(Blocks::getNames)
.filter(Objects::nonNull)
.anyMatch(list->list.contains("blurb"));
You can also add simple null for existing code
private boolean containsText(List<Blocks> blocks) {
return Optional.ofNullable(blocks)
.map(Collection::stream)
.map(o -> o.map(Blocks::getNames).filter(Objects::nonNull))
.map(e -> e.anyMatch(names -> names.contains("blurb")))
.orElse(false);
}

Filter values from Java stream on condition that a value is null

I am trying to get values out of a stream if they meet a certain criteria OR if a certain value is null:
for (ProjectTask task : tasks) {
TaskEnrollmentUpdateRequest updateTask = updatedPhase.getTasks().stream()
.filter(t -> task.getId().equals(t.getId()) || t.getId() == null).findFirst().get();
if (updateTask != null) {
if (updateTask.getId() != null) {
mapper.map(updateTask, task);
} else {
TaskEnrollmentUpdateRequest ted = updateTask;
}
}
...
}
The idea is that I will update task with the values in updateTask if updateTask already exists in the tasks array i.e. its id value is present on an object in that array. If the id is null, which it will be if this a new task, then I want to create a new task to add to the tasks array. Problem is my filter function is filtering out all values that have a null Id so I can never add them to the tasks array.
Is this the correct function to filter out the values as I have described above?:
t -> task.getId().equals(t.getId()) || t.getId() == null
Following along from what #JBNizet says, I think you want something like this:
for (ProjectTask task : tasks) {
Optional<TaskEnrollmentUpdateRequest> updateTaskOptional = updatedPhase.getTasks().stream()
.filter(t -> task.getId().equals(t.getId()) || t.getId() == null).findFirst();
if (updateTaskOptional.isPresent()) {
TaskEnrollmentUpdateRequest updateTask = updateTaskOptional.get();
if (updateTask.getId() != null) {
...
} else {
...
}
}
}
If your filter results in an empty List, then .findFirst() will return an empty Optional, and calling .get() on it will throw an exception since it has no value. So you have to check for that case specifically by checking if the Optional returned by .findFirst() contains a value rather than assuming that it always will.
You can try this:
tasks.stream()
.flatMap(task -> updatedPhase.getTasks().stream().map(ut -> Map.entry(task, ut)))
.filter(e -> e.getValue().getId() == null || e.getKey().getId().equals(e.getValue().getId()))
.findFirst().ifPresent(e -> {
if (e.getValue().getId() != null) {
mapper.map(e.getValue(), e.getKey());
} else {
TaskEnrollmentUpdateRequest ted = e.getValue();
}
});

Java 8 streams nonNull on properties of objects

I have the following snippet that collects specific objects which have a name string property that contains a specific filter filterName.
List<Foo> filteredFoo= fooList.stream()
.filter(Objects::nonNull)
.filter(myFoo -> {
if (Strings.isNullOrEmpty(myFoo.getName()))
return false;
return myFoo.getName().contains(filterName);
}
).collect(Collectors.toList());
It works as expected but I was wondering whether is there a more elegant way to write the if-statement in a functional way and check for empty or null properties in a nicer fashion than having the conditional block in the filter.
Replace second filter with following:
.filter(myFoo -> Optional.ofNullable(myFoo.getName())
.filter(n -> n.contains(filterName))
.isPresent())
or even:
.filter(myFoo -> {
String name = myFoo.getName();
return name != null && name.contains(filterName)
})
Go for the functional style, for the result expression:
.filter(foo -> foo.getName() != null && foo.getName().contains(filterName))
Splitting would not bring more simplicity:
.filter(foo -> foo.getName() != null)
.filter(foo -> foo.getName().contains(filterName))
Using predicates on Foo::getName (Objects::isNull) is senseless complicated too, just in order to spare a variable.
If filterName is not empty itself, Strings.isEmptyOrNull is not needed.
If you have access to Foo Class then move the if conditions to a method isSameName and use filter as below
filter(myFoo -> {return myFoo.isSameName(filterName);})

Categories

Resources