This question already has answers here:
Dealing with a null attribute using java 8 streams and sorting using lambda expressions
(6 answers)
Closed 1 year ago.
What is the best way to check if d1.getDept() and d2.getDept() are null in the following lambda before doing the compare? Should the null check be done before the Collections.sort() or can it be done within the lambda statement?
if (sortBy.contains("Dept")) {
Collections.sort(inventoryVariances, (d1, d2) -> d1.getDept().compareTo(d2.getDept()));
}
I need to ensure the Dept data is not null for each object prior to trying to sort by Dept.
you can try filtring empty values :
inventoryVariances
.stream()
.filter(c -> c.getDept() !=null)
.sort((d1, d2) -> d1.getDept().compareTo(d2.getDept())
Duplicate of Dealing with a null attribute using java 8 streams and sorting using lambda expressions
Straight answer is "no" the collections does not support null values. The use of java 8 comparator nullfirst and nullLast also can be a tricky case for collections as the documentation suggests:
"If the specified comparator is null, then the returned comparator considers all non-null values to be equal."
The simplest way though would be to filter out nulls first:
Assuming that your collection on which you are sorting is an arraylist and you are converting it to another sorted list you can do something like:
inventoryVariances.stream().filter(d -> d.getDept() !=null).sorted(Variance::getDept).collect(Collectors.toCollection(LinkedList::new ));
Related
This question already has answers here:
Why can a method be called on another method?
(7 answers)
Java Pass Method as Parameter
(17 answers)
Closed 1 year ago.
Can some please help me with syntax of following java code?
list.stream()
.filter(name -> name.startsWith("f"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);`
is method filter(name -> name.startsWith("f") is being called on the result of list.stream() and then .map(String::toUpperCase) is being called on its result ? What version of java is this? Where I can read about this more?
Your code snippet is a Java stream, and consists of a pipeline of several processing steps. Here is an explanation:
list.stream()
.filter(name -> name.startsWith("f")) // retain only names starting with 'f'
.map(String::toUpperCase) // map the name to uppercase
.sorted() // sort the stream ascending by name
.forEach(System.out::println); // print out each name
In plain English, this stream says to take an input list of names, remove any name not starting with 'f', uppercase all names, sort them ascending by name, and finally print out each name to the console.
In answer to your question, the lambda you're seeing (name -> name.startsWith("f")) is a feature added in Java 8. This version of Java also adds method references, which are essentially a quicker way to write many lambdas which merely call an existing method. The line .map(String::toUpperCase) could have been written as .map(name -> name.toUpperCase()). Similarly .forEach(System.out::println) could have been .forEach(name -> System.out.println(name)).
Documentation on Oracle.com for further reading:
Lambda Expressions
Method references
list.stream()
.filter(name -> name.startsWith("f"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
The whole idea of Java streams is to enable functional-style operations on streams of elements, using Lambda experession and Method reference.
Method references are a special type of lambda expressions
In functional-style operations the execution is performed from left to right that means
stream() is called on result of list
filter() is called on result of list.stream()
map() is called on result of list.stream().filter(name -> name.startsWith("f"))
sorted() is called on result of list.stream().filter(name -> name.startsWith("f")).map(String::toUpperCase)
forEach is called on the result of list.stream().filter(name -> name.startsWith("f")).map(String::toUpperCase).sorted()
To explore your knowledge you can read from Oracle Java (version 8 onward) Documents
Specially for the topics Lambda expression and method reference :-
1. Lamda Expression
2. Method Reference
The stream is one of the functional element of Java which uses Lambda Expressions (unnamed function).
You have a list and convert it to a stream.
For each element you will use the filter function which removes the elements that do not safisfy the criteria. This selection criteria is given as a Lambda Function. Its argument is the element and it should return with a boolean value. So the name should start with 'f'.
Then you use the 'map' function to convert the elements of the list into another type using a Lambda Function again. In this case your list contains string and your LambadaFunction is the String::toUpperCase. This a short hand format of (name) -> {return String.toUpperCase(name);}. In other words, the toUpperCase function will be called with each element of the list and the 'map' will produce a new stream which contains the results.
Next you sort the stream.
Finally, Each element of the stream is given as an argument of the 'println' method.
The result should contains a sorted list of names starting with F.
This question already has answers here:
Java 8 Distinct by property
(34 answers)
Closed 2 years ago.
I'm trying to make a filter that filters for distinct objects with the same 2 properties.
I know there are other ways to do this with distinct but I would like to do it with a filter inside a filter. I have following code:
filteredOrderLines.stream().filter(o -> filteredOrderLines.stream().filter(o2 -> o.getOrderId().equals(o2.getOrderId()) && o.getProductId().equals(o2.getProductId()))).collect(Collectors.toList());
I'm getting:
Bad return type in lambda expression: Stream<OrderLineDTO> cannot be converted to boolean
More correct way to solve this task is to override equals and hashCode methods inside your Order class (include both orderId and productId fields) and call distinct() method on your stream. Stream chain will look like this:
List<Order> uniqueOrders = filteredOrderLines.stream()
.distinct()
.collect(Collectors.toList());
And event more correct solution - use HashSet to remove duplicates from your initial list.
This question already has an answer here:
null-safe mapping Comparator using default implementations
(1 answer)
Closed 3 years ago.
I am using comparators lambda expression to sort date in long format.
Comparator's comparingLong method is used to sort list of date objects in long format (milliseconds).
It sorts the dates properly, but the problem is that whenever a null value is encountered in date object, it breaks and throws a null pointer exception.
Can you please help me to avoid this, either by using any check in lambda expression, because I don't know how this check can be used in lamda expression, or is there any other way to avoid this exception?
Below lambda expression is used.
How will we impose null check in this, so that all the null date values comes at the end of the list and code does not break?
myList.sort(Comparator.comparingLong(e -> e.getBirthDate().getTime()));
e ->null == e.getBirthDate()? LONG.MINIMUM : e.getBirthDate().getTime()
This question already has answers here:
Java 8 lambdas, Function.identity() or t->t
(3 answers)
Closed 3 years ago.
Have been through some code and ran into Function.identity() which I found it is similar to s->s. I do not understand why and when I should use Function.identity().
I have tried to understand by working on an example, but it did not clarify my questions:
public static void main(String[] args){
Arrays.asList("a", "b", "c")
.stream()
.map(Function.identity())
//.map(str -> str) //it is the same as identity()
.forEach(System.out::println);
return;
}
When printing the list elements with and without mapping, I am getting the same result:
a
b
c
So, what is the purpose of including s-> s which is passing a string and retrieving an string? what is the purpose of Function.identity()?
Please provide me with a better example, maybe this example does not make sense to prove the importance of using identity().
Thanks
It's useful when the API forces you to pass a function, but all you want is to keep the original value.
For example, let's say you have a Stream<Country>, and you want to make turn it into a Map<String, Country>. You would use
stream.collect(Collectors.toMap(Country::getIsoCode, Function.identity()))
Collectors.toMap() expects a function to turn the Country into a key of the map, and another function to turn it into a value of the map. Since you want to store the country itself as value, you use the identity function.
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 4 years ago.
I have made a class called User with two string attributes: Login and Password.
I have a database (userList, of type ArrayList<User>) with all the existing users, and I want to know if a login is already used or not.
I tried to use lambda expressions in order to do that, but it doesn't work:
ArrayList<String> loginList = null;
userListe.forEach(x->loginList.add(x.getLogin()));
How do I solve this?
Assuming userListe is a List:
List<String> loginList = userListe
.stream()
.map(x -> x.getLogin())
.collect(Collectors.toList));
Explanation:
It is better to use a List instead of ArrayList because it is always preferable using interface instead of concrete types. First, using a stream you create a flow of User objects. Using map you get a field from your objects using the appropriate getter. At last, using a collect you can collect all objects returned by map method, in this case String object.
Your loginList is null, so the first forEach will throw a NullPointerException. Also, remember that it is better to have pure function in lambdas, with no side effects. Using stream and collect allows you to get a List of objects you need without having functions with side effects.