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.
Related
This question already has answers here:
How to make a CaseInsensitiveConcurrentMap?
(2 answers)
Closed 2 years ago.
So basically I have treeMap and I want to find keys in it the thing is that searching for ABC or Abc or aBc or abC or ABc or AbCor aBC it should return true in the containsKey after using some comparator i think.
The thing is that i already tried to covert the String all into lower case and upper case but sometimes i need the key to be like aBC because i need to print the key and printing abc and ABC or ABc are different things.
So do you know another way to do this?
Use toLower() when adding to the map, and also when searching. But, you'll have to add special handling if you want to be able to store distinct values for keys that differ only in upper/lower case.
If you need to keep the original case you'll have to modify the value object to store it.
You might also want to subclass TreeMap and override the put and get methods to take care of the toLower() calls. Remember to override ALL methods that get or put values.
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 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.
This question already has answers here:
How to sort an ArrayList with object using stream().sorted()
(5 answers)
Closed 5 years ago.
So I have an assignment to sort a certain List using the Comparator and using the lambda together with the stream method, and after that I must compare the time needed to sort the list using the comparator vs. the lambda and stream combination.
Let's say that I have a Communication class which has the commTime and a Client attributes (the Client has a getSurname method).
Now, in the app, I must sort the communications list using the two above methods. I've already done the one using the Comparator, but I'm having trouble using the lambda and stream method.
I have something like this:
Collections.sort(communications, (comm1, comm2) -> comm1.getCommTime().compareTo(comm2.getCommTime()));
This will go under an if statement (if the time is not equal), but if it is equal, I must sort the list by comparing surnames of the clients in the communication. I don't know how to do that, more precisely - I don't know how to reach the client's surname from the communication itself.
I can't do this:
Function<Communication, LocalDateTime> byTime = Communication::getCommTime;
Function<Communication, String> bySurname = Communication.getClient()::getSurname;
Comparator<Communication> byTimeAndSurname = Comparator.comparing(byTime).thenComparing(bySurname);
communications.stream().sorted(byTimeAndSurname);
but I have no idea what can I do.
For the part of the app where I have to determine the length of sorting, I know how to that, so no need on explaining that part (at least I know how to do something, right?).
There are few problems with Communication.getClient()::getSurname;. Since .getClient() is not static you can't use it as Communication.getClient(). Another problem is that it would create method reference for one object which would be returned from getClient() at time of creating this method reference.
Simplest way would be using lambda expression like
Function<Communication, String> bySurname = com -> com.getClient().getSurname();
BTW communications.stream().sorted(byTimeAndSurname); sorts stream, not its source (communications). If you want to sort communications you should use
Collections.sort(communications, byTimeAndSurname);
Other way of achieving A->C mapping via A->B->C is using
someAToBFunction.andThen(someBToCFunction)
^^^^^^^
(documentation). In your case you could write
Function<Communication, Client> byClient = Communication::getClient;
Function<Communication, String> bySurname = byClient.andThen(Client::getSurname);
Or as (uglier) "one-liner":
Function<Communication, String> bySurname =
((Function<Communication, Client>)Communication::getClient)
.andThen(Client::getSurname);
This question already has answers here:
How do I determine whether an array contains a particular value in Java?
(30 answers)
Closed 6 years ago.
I have a similar logic for a method in a Java Class (not the real code, this is simplified for example purposes).
private Boolean method(Boolean booleanValue, SomeObject object) {
return booleanValue ? Arrays.asList(object.getStringsArray()).contains("string") : false;
}
A collaborator who assigned himself to check the PR gave the following comment:
This is inefficient. It is creating a new data structure only to iterate it and check if there is a certain string.
The getStringsArray() method returns a String[], so will using a for-loop be better than Arrays.asList()?
Which way is more efficient to achieve this?
Your co-worker is incorrect when they assert that your method is creating a new data structure.
If you look at the API for Arrays.asList(), it says that it
Returns a fixed-size list backed by the specified array.
There is no reason to write your own code to iterate over the array when you can just wrap a List around it, and use its built-in methods.