Hi, dear readers! Welcome to my blog. On this post, we will continue our tour on Java 9, now focusing on what changed on Streams and Optionals.
Creating collections
Before Java 9, when we wanted to populate a collection with some data, we commonly would do this:
Map<Long,String> tasks = new HashMap<>(); tasks.put(1l,"Put trash on the street"); tasks.put(2l,"Buy bread"); tasks.put(3l,"Walk with the dog"); tasks.put(4l,"make dinner");
Of course, we could also create the collection like this:
Map<Long, String> tasks = new HashMap<>() {{ put(1l, "Put trash on the street"); put(2l, "Buy bread"); put(3l, "Walk with the dog"); put(4l, "make dinner"); }};
Still, it is quite a verbose way to create a collection. Finally, on Java 9, we can create a collection this way, much more cleaner:
Map<Long, String> tasks = Map.of( 1l, "Put trash on the street", 2l, "Buy bread", 3l, "Walk with the dog", 4l, "make dinner" );
Two points are worth note about the of method, however:
- There’s no way to choose which implementation will be used;
- If there is any null values on the data, the creation will fail with a NullPointerException;
New collectors
Another good addition was the new collectors. With them, we can now apply filters or mappers to streams inside of the collecting. Let’s see some examples.
Let’s use the same tasks map from before. Let’s suppose the want a list of task values, filtered by only taks that doesn’t have the word dog. With the new collectors, we can accomplish this by doing:
tasks.values().stream().collect(Collectors.filtering(w -> !w.contains("dog"), Collectors.toList())).forEach(System.out::println);
If we execute the code, we will see that it will print all the tasks except the one about walling with the dog, as we expected.
Now, let’s see another example. Let’s suppose we want to create a list with only the first word of each task. This can be done by using the following code:
tasks.values().stream().collect(Collectors.mapping(w -> w.split(" ")[0], Collectors.toList())).forEach(System.out::println);
If we run the code, we will see that it will print a list with just the first words from the tasks, as we expected.
Iterating with streams
Another interesting new feature included was the dropwhile and takewhile operations. By using them, we can iterate sequentially on collections, discarding or including items while a predicate is not satisfied. Let’s see some examples.
Let’s begin by creating a collection for our tests:
List<String> words = List.of("we", "are", "testing", "new", "features", "of", "Java", "9");
Now, let’s try the dropwhile:
words.stream().dropWhile(e -> !e.equals("new")).forEach(System.out::println);
The result if we execute our stream will be as follows:
new features of Java 9
As we can see, it is the correct result, since we ordered the stream to drop items from our iteration while none of them are equals to “new”.
If we try the takewhile operation, with the same predicate, we will see that the stream will store the items while a item equals to “new” is not found, exactly as expected. This is the code modified for the new example:
words.stream().takeWhile(e -> !e.equals("new")).forEach(System.out::println);
And this is the new result:
we are testing
New features on Optionals
Optionals also get their share of improvements. Let’s begin with our previous example from the mapping collector.
Let’s suppose our tasks map uses Optionals for values instead of literal strings:
Map<Long, Optional<String>> tasks = Map.of( 1l, Optional.ofNullable("Put trash on the street"), 2l, Optional.ofNullable("Buy bread"), 3l, Optional.ofNullable("Walk with the dog"), 4l, Optional.ofNullable("make dinner") );
If we wanted to use the same map to implement the previous stream, we would have to “extract” all the values from the optionals previous to using them on the stream. That is, until Java 9.
Now, we can implement the previous stream on this new scenario by doing this:
tasks.values().stream().flatMap(Optional::stream).collect(Collectors.mapping(w -> w.split(" ")[0], Collectors.toList())).forEach(System.out::println);
If we run our code, we will see that it will print the list with just the first words from the tasks, just like before.
Another good addition was the ifpresentorelse method. Now, if we need to implement logic that depends if a Optional is empty or not, we can just do:
myOptional.ifPresentOrElse(present -> System.out.println(present), () -> { System.out.println("nothing to do"); });
And even more interesting, now Optionals supports the or method, that allows us to create multiple fallback returns! We can see the method in action on the example bellow:
myOptional.or(() -> Optional.ofNullable("this is my first callback")) .or(() -> Optional.ofNullable("this is my second callback")) .or(() -> Optional.ofNullable("this is my third callback")) .or(() -> Optional.ofNullable("this is my fourth callback"));
Conclusion
And so we concluded another post from our series on the new features of Java 9. Please, stay tuned on my series, where we will talk about other features, such as the long waited Jigsaw. Thank you for following me on another post, thank you.