I am trying to apply stream on a list which can be null as it is calling a repository method and I want to get the first element from it if it is not null and compare one of its parameter with request value.
Optional.ofNullable(placementRepository.findAllByAccountId(accountId))
.orElseGet(Collections::emptyList)
.stream()
.filter(Objects::nonNull)
.findFirst()
.get()
.getPlacementDate()
.isAfter(placementRequest.getPlacementDate())
Currently it is failing at .get if the list itself is null though I filtered with nonNull. I want stream the list if the list is not null and get the first element and compare its parameter against other value. I tried with other alternative filters but no luck
I want stream the list if the list is not null and get the first
element and compare its parameter against other value.
You didn't think of the case of empty or null elements in the returned List of the repository. You have to choose a default value or execute the date comparison only if the optional is present.
For example with a default date value :
final LocalDate defaultDateValue = ...;
Optional.ofNullable(placementRepository.findAllByAccountId(accountId))
.flatMapping(l -> l.stream()
.filter(Objects::nonNull)
.findFirst()
.mapping(o -> o.getPlacementDate())
)
.orElse(defaultDateValue)
.isAfter(placementRequest.getPlacementDate())
With a conditional processing :
Optional<LocalDate> opt =
Optional.ofNullable(placementRepository.findAllByAccountId(accountId))
.flatMapping(l -> l.stream()
.filter(Objects::nonNull)
.findFirst()
.mapping(o -> o.getPlacementDate())
)
if (opt.isPresent()){
boolean isAfter = opt.get().isAfter(placementRequest.getPlacementDate());
// ...
}
Optional<T> findFirst();, so in case you have null or empty stream, then this method returns null.
You should use .findFirst().orElseGet(() -> /* NULL object*/)
The thing is that .findFirst() is able to return no result at all and .get() will fail. You can use .ifPresent() or use .orElseGet()
Considering the type of elements in your list is YourPojo, this code snippet should do what you need:
List<YourPojo> list = placementRepository.findAllByAccountId(accountId);
LocalDate date = placementRequest.getPlacementDate();
boolean flag =
Optional.ofNullable(list) // Optional<List<YourPojo>>
.flatMap(Collection::stream) // Stream<YourPojo>
.filter(Objects::nonNull) // Stream<YourPojo>
.findFirst() // Optional<YourPojo>
.map(YourPojo::getPlacementDate) // Optional<LocalDate>
.map(d -> d.isAfter(date)) // Optional<Boolean>
.orElse(false); // Boolean
Note: If you're using Java 11 or above then .map(d -> d.isAfter(date)) can be replaced by .map(not(date::isBefore)). Not sure if it's more readable though.
Related
In my method below, the variable n can be null, and if it is null I want to return an empty list eg something like List.of. How can I amend the below method to ensure that if a null is found, an empty List is returned and not removed? I tried using filter which I've commented out below, but that just removes any instances where null is found.
private List<Account> getNames(MetaData metadata){
return metadata.getNames()
.stream()
.map(n -> createAccount(n, metadata.getType()))
//.filter(n -> n.getFinalName() != null)
.collect(Collectors.toList());
}
private Account createAccount(String n, Metadata metadata){...}
You can use ternary operator
return metadata.getNames()
.stream()
.map(n -> n!=null ? createAccount(n, metadata.getType()) : /* else do something */)
.collect(Collectors.toList());
I have a piece of code where am doing something like:
Optional<College> college = Optional.ofNullable(student)
.map(stud -> stud.getCollege())
.get()
.stream()
.filter(college -> Objects.nonNull(college.getCollegeName()))
.findFirst();
Now, while writing an unit test, I got a catch that what if student comes as null?
It would be effectively like:
Optional.empty() // the same as the student is null
.map(stud -> stud.getCollege())
.get()
.stream()
.filter(college -> Objects.nonNull(college.getCollegeName()))
.findFirst();
Which I think is not fine because I am getting Exception
expected<com.src.exceptions.CollegeNotFoundException> but
was<java.util.NoSuchElementException>
#Update
Updating the question details for clarifications
Yes stud.getCollege() returns a list<>
I agree with #Nikolas approach except that you should not return null, returning null at last is against using Optional
What about this one:
Optional<College> optional = Optional.ofNullable(student)
.map(stud -> stud.getCollegeList())
.orElse(Collections.emptyList())
.stream()
.filter(c -> Objects.nonNull(c.getCollegeName()))
.findFirst();
Calling Optional::get with no previous check Optional::isPresent is dangerous because it might produce CollegeNotFoundException. And it is not the way the Optional shall be used. The idea of Optional is mapping/filtering the values and providing a default value if the Optional ends up with no element (empty).
Assuming Student::getCollege returns List<College> having method College::getCollegeName, you can do the following:
College college = Optional.ofNullable(student)
.map(stud -> stud.getCollege())
// if Optional is empty, then use an empty collection
.orElse(Collections.emptyList())
.stream()
.filter(c -> Objects.nonNull(c.getCollegeName()))
.findFirst()
// get the value or else college is null
.orElse(null);
As long as stud.getCollege() returns null, the Optional becomes empty and an empty list will be streamed. And again the same principle is applied: As long as the list is empty, the filter and findFirst are not be called and null is safely returned (or any default value you wish).
Also note that the line .filter(c -> Objects.nonNull(c.getCollegeName())) might also produce NullPointerException as long as there is not guaranteed stud.getCollege() doesn't return a list with a null element (remember the list is not null itself so Optional treats it as a "valuable" item). The safe code actually looks like:
Optional<College> college = Optional.ofNullable(student)
.map(stud -> stud.getCollege())
.orElse(Collections.emptyList())
.stream()
.filter(c -> c != null && c.getCollegeName() != null)
.findFirst();
Actually, I prefer to return either a null-object, null or Optional itself.
I am getting list of objects from API
public Optional<List<Employee>> getEmployeeData (String deptId){
List<Employee> employee = departmentClient.employeeData(deptId);
//Based on some condition I am filtering employee list but before that I want to check for null for list.
return Optional.ofNullable(employee).orElse(Collections.emptyList())
.stream()
.filter(Objects::nonNull)
.filter(e -> e.getType != null)
.collect(Collectors.toList());
}
But I think as method return type is Optional<> this is giving error. How can I check null for the List before the Stream and return as an Optional<List<..>>
You returned List<Employee> while your method signature is Optional<List<Employee>>
Try this one:
return employee != null ? Optional.of(employee.stream()
.filter(Objects::nonNull)
.filter(e -> e.getType != null)
.collect(Collectors.toList())) : Optional.ofNullable(Collections.emptyList());
Your solution doesn't work because the result of Optional is List and you collect it through the Stream pipelines back to the List.
Using Java 8 you can wrap all your solution inside Optional or better use the advantage of the Collectors instead:
Optional<List<Employee>> o = Optional
.ofNullable(employees) // employees can be null, right?
.orElse(Collections.emptyList()) // ... if so, then empty List
.stream() // Stream<Employee>
.filter(Objects::nonNull) // Stream<Employee> filtered as non-nulls
.filter(e -> e.getType() != null) // Stream<Employee> with non-null field
.collect(Collectors.collectingAndThen(
Collectors.toList(), // Collected to List<Employee>
Optional::of)); // Collected to Optional<List<Employee>>
The Collectors::collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher) method behaves as usual Collector providing a subsequent mapping function taking the collected result. In our case, we simply wrap the List into Optional to be returned.
Collector downstream collects to List<Employee>
Function finisher maps List<Employee> to Optional<List<Employee>>
With Java 9 and higher using Optional::stream, the beginning might be little different:
Optional<List<Employee>> o = Optional
.ofNullable(employees) // null-safe employees
.stream() // Stream<List<Employees>>
.flatMap(List::stream) // Stream<Employees>
.filter(Objects::nonNull)
......
And yet another option:
return Optional.ofNullable(employee)
.map(list -> list.stream()
.filter(Objects::nonNull)
.filter(e -> e.getType() != null)
.collect(Collectors.toList()));
The lambda inside .map(...) is executed only if the emploee list is not null, otherwise an empty Optional is returned.
So, I have an ArrayList of autogenerated strings. I want to find the first element that contains some character or else if there is no one element that matches this filter, to apply another filter. In another way, I want to return null object.
So I write this lambda expression:
str.stream()
.filter(s -> s.contains("q"))
.findFirst()
.orElseGet(() -> str.stream()
.filter(s -> s.contains("w"))
.findFirst()
.orElseGet(null))
But if there is no one element that matches this two filters I will have NullPointerException. How, can I get something like: return null?
Unless I'm missing something obvious, simply .orElse(null) instead of the last orElseGet. orElseGet accepts a Supplier and you pass a null, calling get() on a null reference, well...
An additional, simpler approach: you can filter on strings containing q or w, then sort to move those containing q first, find first, return null if the optional is empty:
str.stream()
.filter(s -> s.contains("q") || s.contains("w"))
.sorted((s1, s2) -> s1.contains("q") ? -1 : 1 )
.findFirst()
.orElse(null);
.sorted((s1, s2) -> s1.contains("q") ? -1 : 1 ) will move the strings containing "q" first. Since the stream has been filtered only on values containing either q or w, then returning null will only happen no element is retained.
The problem is Optional::orElseGet(null) which accepts a Supplier<T> and throws the NullPointerException.
Use the Optional::orElse(null) which accepts T which is String in your case.
The following code works:
List<String> str = Arrays.asList("a", "b", "c");
String output = str.stream()
.filter(s -> s.contains("q"))
.findFirst()
.orElseGet(() -> str.stream()
.filter(s -> s.contains("w"))
.findFirst()
.orElse(null)); // <-- HERE
System.out.println(output); // Prints null
Alternatively, use the Optional::orElseGet(Supplier<? extends T> other) to return null. The Supplier itself must be not null:
.orElseGet(() -> null));
orElseGet expects a Supplier, you need to pass a value, which is the case for orElse.
I wouldn't use Stream API here, one iteration is enough to solve the problem:
String wString = null;
for (String s : str) {
if (s.contains("q")) return s;
if (s.contains("w") && wString == null) wString = s;
}
return wString;
Using Java 8 stream what is the best way to map a List<Integer> when you have no output for the input Integer ?
Simply return null? But now my output list size will be smaller than my input size...
List<Integer> input = Arrays.asList(0,1,2,3);
List<Integer> output = input.stream()
.map(i -> {
Integer out = crazyFunction(i);
if(out == null || out.equals(0))
return null;
return Optional.of(out);
})
.collect(Collectors.toList());
I don’t get why you (and all answers) make it so complicated. You have a mapping operation and a filtering operation. So the easiest way is to just apply these operation one after another. And unless your method already returns an Optional, there is no need to deal with Optional.
input.stream().map(i -> crazyFunction(i))
.filter(out -> out!=null && !out.equals(0))
.collect(Collectors.toList());
It may be simplified to
input.stream().map(context::crazyFunction)
.filter(out -> out!=null && !out.equals(0))
.collect(Collectors.toList());
But you seem to have a more theoretical question about what kind of List to generate, one with placeholders for absent values or one with a different size than the input list.
The simple answer is: don’t generate a list. A List is not an end in itself so you should consider for what kind of operation you need this list (or its contents) and apply the operation right as the terminal operation of the stream. Then you have your answer as the operation dictates whether absent values should be filtered out or represented by a special value (and what value that has to be).
It might be a different answer for different operations…
Replace the map call with flatMap. The map operation produces one output value per input value, whereas the flatMap operation produces any number of output values per input value -- include zero.
The most straightforward way is probably to replace the check like so:
List<Integer> output = input.stream()
.flatMap(i -> {
Integer out = crazyFunction(i);
if (out == null || out.equals(0))
return Stream.empty();
else
return Stream.of(out);
})
.collect(Collectors.toList());
A further refactoring could change crazyFunction to have it return an Optional (probably OptionalInt). If you call it from map, the result is a Stream<OptionalInt>. Then you need to flatMap that stream to remove the empty optionals:
List<Integer> output = input.stream()
.map(this::crazyFunctionReturningOptionalInt)
.flatMap(o -> o.isPresent() ? Stream.of(o.getAsInt()) : Stream.empty())
.collect(toList());
The result of the flatMap is a Stream<Integer> which boxes up the ints, but this is OK since you're going to send them into a List. If you weren't going to box the int values into a List, you could convert the Stream<OptionalInt> to an IntStream using the following:
flatMapToInt(o -> o.isPresent() ? IntStream.of(o.getAsInt()) : IntStream.empty())
For further discussion of dealing with streams of optionals, see this question and its answers.
Simpler variants of #Martin Magakian 's answer:
List<Integer> input = Arrays.asList(0,1,2,3);
List<Optional<Integer>> output =
input.stream()
.map(i -> crazyFunction(i)) // you can also use a method reference here
.map(Optional::ofNullable) // returns empty optional
// if original value is null
.map(optional -> optional.filter(out -> !out.equals(0))) // return empty optional
// if captured value is zero
.collect(Collectors.toList())
;
List<Integer> outputClean =
output.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList())
;
You can wrap the output into an Optional which may or may not contain a non-null value.
With an output: return Optional.of(out);
Without output: return Optional.<Integer>empty();
You have to wrap into an option because an array cannot contain any null value.
List<Integer> input = Arrays.asList(0,1,2,3);
List<Option<Integer>> output = input.stream()
.map(i -> {
Integer out = crazyFunction(i);
if(out == null || out.equals(0))
return Optional.<Integer>empty();
return Optional.of(out);
})
.collect(Collectors.toList());
This will make sure input.size() == output.size().
Later on you can exclude the empty Optional using:
List<Integer> outputClean = output.stream()
.filter(Optional::isPresent)
.map(i -> {
return i.get();
})
.collect(Collectors.toList());