List<String> to List<Integer> using Integer foo(String s) - java

I've got a list List<String> (list1) and a function Integer foo(String s). Using the power of Java 8 I want to convert list1 to a List<Integer> by applying foo to each item of list1. The following code works but has a little problem:
List<Integer> list2 = list1.stream().mapToInt(s -> foo(s)).boxed().collect(Collectors.toList());
When fooreturns null for some element of list1 a NullPointerExceptionis thrown. Additionally my solution looks a little bit inconvenient. So is there a better one?

If you are mapping it to an Integer, I don't see the need to use mapToInt and then use boxed.
Instead, you could simple use map and then filter to exclude the nulls.
List<Integer> list2 =
list1.stream()
.map(s -> foo(s))
.filter(Objects::nonNull)
.collect(Collectors.toList());
If you want to keep the nulls in the list, simply remove the filter
List<Integer> list2 =
list1.stream()
.map(s -> foo(s))
.collect(Collectors.toList());

As an alternative to the answer already given, you can do this:
List<Integer> list2 = new ArrayList<>();
list1.forEach(s -> list2.add(foo(s)));

Related

How to i compare two lists of different types in Java?

I have two lists:
The first list is a list of MyObject which contains an int and a String:
List<MyObject> myObjList = new ArrayList<>();
myObjList.add(new MyObject(1, "Frank"));
myObjList.add(new MyObject(2, "Bob"));
myObjList.add(new MyObject(3, "Nick"));
myObjList.add(new MyObject(4, "Brian"));
The second list is simply a list of strings:
List<String> personList = new ArrayList<>();
personList.add("Nick");
I want to compare the list of strings (personList) with string in the list of MyObject (myObjectList) and return a list of id's with all the matches. So in the examle it should return a list containing only Nicks id -> 3. How do I do that?
UPDATE:
To get a list of id's I simply said:
myObjectList.stream()
.filter(mo -> personList.contains(mo.id))
.map(MyObject::id)
.collect(Collectors.toList());
I'm not entirely clear which way round you want, but if you want the elements in personList which are ids of elements in myObjList:
personList.stream()
.filter(s -> myObjList.stream().anyMatch(mo -> mo.id.equals(s)))
.collect(Collectors.toList());
or, if you want the elements in myObjList whose ids are in personList:
myObjectList.stream()
.filter(mo -> personList.contains(mo.id))
.collect(Collectors.toList());
(In the latter case, it may be better for personList to be a Set<String>).

How to use the Optional.ofNullable and Stream

I am doing a test case to use Optional.ofNullable and Stream together, and I faced to ways to do the same, both have the same output.
List<String> list1 = List.of("abc","abc");
Optional.ofNullable(list1).stream().flatMap(List::stream).map(e -> e.concat("def")).collect(Collectors.toList());
List<String> list2 = List.of("abc","abc");
Stream<String> stream = Optional.ofNullable(list2).map(List::stream).orElseGet(Stream::empty);
stream.map(e-> e.concat("def")).collect(Collectors.toList());
My question is, why at the first example I use a flatMap and a map and at the second one I use two map's to do the same job. If I try to use two map's at the first example it doesn't work.
To understand what's happening it can help to look at all the return types:
First example:
List<String> list1 = List.of("abc","abc");
List<String> result =
Optional.ofNullable(list1) // Optional<List<String>>
.stream() // Stream<List<String>>
.flatMap(List::stream) // Stream<String>
.map(e -> e.concat("def")) // Stream<String>
.collect(Collectors.toList()); // List<String>
In this example you go straight from an Optional<List<String>> to a Stream<List<String>> and then use the methods of the latter interface. The methods used here are (in order):
Optional#ofNullable(T)
Optional#stream()
Stream#flatMap(Function)
Stream#map(Function)
Stream#collect(Collector)
Second example:
List<String> list2 = List.of("abc","abc");
List<String> result =
Optional.ofNullable(list2) // Optional<List<String>>
.map(List::stream) // Optional<Stream<String>>
.orElseGet(Stream::empty); // Stream<String>
.map(e-> e.concat("def")) // Stream<String>
.collect(Collectors.toList()); // List<String>
In this example you go from an Optional<List<String>> to an Optional<Stream<String>> (another optional) and then extract the Stream<String> via Optional#orElseGet(Supplier). Afterwards, you use the methods of the Stream interface. The methods used here are (in order):
Optional#ofNullable(T)
Optional#map(Function)
Optional#orElseGet(Supplier)
Stream#map(Function)
Stream#collect(Collector)

How to use java stream map inside java stream filter

I have 2 arrays and want to make a list of role.getRoleName() only with elements that are in both arrays using streams.
final List<String> roleNames = new ArrayList<>();
roleNames = Arrays.stream(roles).filter(role -> role.getRoleId()
== Arrays.stream(permissions).map(permission -> permission.getRoleId()));
when I write the above code I get
Operator '==' cannot be applied to 'int', 'java.util.stream.Stream'
I understand the error, but I don't know the solution of how to make the permissions stream in only permission.getRoleId integers.
There is no way to compare such incompatible types as int and Stream.
Judging from what you've shown, Stream#anyMatch might a good candidate.
roleNames = Arrays.stream(roles)
.map(Role::getRoleId)
.filter(id -> Arrays.stream(permissions).map(Role::getRoleId).anyMatch(p -> p.equals(id)))
.collect(Collectors.toList());
This part Arrays.stream(permissions).map(Role::getRoleId) may be pre-calculated and stored into a Set.
final Set<Integer> set = Arrays.stream(permissions)
.map(Role::getRoleId)
.collect(Collectors.toSet());
roleNames = Arrays.stream(roles)
.filter(role -> set.contains(role.getRoleId()))
.map(Role::getRoleName)
.collect(Collectors.toList());
What you can do is collect unique roleIds for the array of Permissions into a Set as a computed result and perform a contains check as you iterate through the array of Roles. This could be done as :
final Set<Integer> uniqueRoleForPermissions = Arrays.stream(permissions)
.map(Permission::getRoleId)
.collect(Collectors.toSet());
final List<String> roleNames = Arrays.stream(roles)
.filter(role -> uniqueRoleForPermissions.contains(role.getRoleId()))
.map(Role::getRoleName)
.collect(Collectors.toList());

Map to List after filtering on Map's key using Java8 stream

I have a Map<String, List<String>>. I want to transform this map to a List after filtering on the map's key.
Example:
Map<String, List<String>> words = new HashMap<>();
List<String> aList = new ArrayList<>();
aList.add("Apple");
aList.add("Abacus");
List<String> bList = new ArrayList<>();
bList.add("Bus");
bList.add("Blue");
words.put("A", aList);
words.put("B", bList);
Given a key, say, "B"
Expected Output: ["Bus", "Blue"]
This is what I am trying:
List<String> wordsForGivenAlphabet = words.entrySet().stream()
.filter(x-> x.getKey().equalsIgnoreCase(inputAlphabet))
.map(x->x.getValue())
.collect(Collectors.toList());
I am getting an error. Can someone provide me with a way to do it in Java8?
Your sniplet wil produce a List<List<String>> not List<String>.
You are missing flatMap , that will convert stream of lists into a single stream, so basically flattens your stream:
List<String> wordsForGivenAlphabet = words.entrySet().stream()
.filter(x-> x.getKey().equalsIgnoreCase(inputAlphabet))
.map(Map.Entry::getValue)
.flatMap(List::stream)
.collect(Collectors.toList());
You can also add distinct(), if you don't want values to repeat.
Federico is right in his comment, if all you want is to get the values of a certain key (inside a List) why don't you simply do a get (assuming all your keys are uppercase letters already) ?
List<String> values = words.get(inputAlphabet.toUpperCase());
If on the other hand this is just to understand how stream operations work, there is one more way to do it (via java-9 Collectors.flatMapping)
List<String> words2 = words.entrySet().stream()
.collect(Collectors.filtering(x -> x.getKey().equalsIgnoreCase(inputAlphabet),
Collectors.flatMapping(x -> x.getValue().stream(),
Collectors.toList())));
As was previously told after collect you will get List<List<String>> with only one or zero value in it. You can use findFirst instead of collect it will return you Optional<List<String>>.

Java 8 stream. all elements EXCEPT other elements

I'm interested in identifying an approach that returns a list of elements excluding the elements in another list.
for example
List<Integer> multiplesOfThree = ... // 3,6,9,12 etc
List<Integer> evens = ... // 2,4,6,8 etc
List<Integer> others = multiplesOfThree.except(evens) // should return a list of elements that are not in the other list
how do you do this?
i found an approach that's a bit clunky and difficult to read....
multiplesOfThree.stream()
.filter(intval -> evens.stream().noneMatch(even -> even.intValue() == intval.intValue()))
You can use Stream's filter method, passing a Predicate that ensures that the element doesn't exist in evens.
List<Integer> others = multiplesOfThree.stream()
.filter(i -> !evens.contains(i))
.collect(Collectors.toList());
But assuming you have a mutable List (e.g. ArrayList), you don't even need streams, just Collections's removeAll method.
multiplesOfThree.removeAll(evens);
You could use
multipleOfThree.stream()
.filter(((Predicate<Integer>) evens::contains).negate())
or more efficient for big even lists
HashSet<Integer> evenSet = new HashSet<>(even);
multipleOfThree.stream()
.filter(((Predicate<Integer>) evenSet::contains).negate())
There are a few solutions.
First, without using streams, you can just create a new list and remove all elements from another collection from it...
final List<Integer> multiplesOfThree = Arrays.asList(3,6,9,12);
final List<Integer> evens = Arrays.asList(2,4,6,8,10,12);
final List<Integer> others1 = new ArrayList<>(multiplesOfThree);
others1.removeAll(evens);
Another solution would be to pass the stream through a filter():
final List<Integer> others2 = multiplesOfThree
.stream()
.filter(x -> !evens.contains(x))
.collect(Collectors.toList());
(You may want to consider making evens a Set in this case).
And finally, you could modify the logic above to represent the "evens" as a function rather than a collection of all even numbers. This is essentially the same as above, but you don't have to have a second collection.
final List<Integer> others3 = multiplesOfThree
.stream()
.filter(x -> x % 2 != 0)
.collect(Collectors.toList());

Categories