An intermediate operation returns a Stream object that emits or not the same or modified value(s) of the same or different type than the stream source. In this installment, we will discuss intermediate operations that change element value and/or type.
The map() operation (method) of the Stream interface transforms the original stream element value to a new one of the same or a different type. It is an intermediate operation as it returns a Stream object:
— Stream<R> map(Function<T, R> mapper). Applies the provided function to each element of type T of the input stream and produces a new element value of type R.
— IntStream mapToInt(ToIntFunction<T> mapper). Applies the provided function to each element of type T of the input stream and produces a new element value of type int.
— LongStream mapToLong(ToLongFunction<T> mapper). Applies the provided function to each element of type T of the input stream and produces a new element value of type long.
— DoubleStream mapToDouble(ToDoubleFunction<T> mapper). Applies the provided function to each element of type T of the input stream and produces a new element value of type double.
— Stream<U> mapToObj(IntFunction mapper). Converts each element of type int of the input stream to a value of type U by applying to it the specified function.
— Stream<U> mapToObj(LongFunction mapper). Converts each element of type long of the input stream to a value of type U by applying to it the specified function.
— Stream<U> mapToObj(DoubleFunction mapper). Converts each element of type double of the input stream to a value of type U by applying to it the specified function.
As you can see, mapTo() operations are just specialized map() operations that can convert a stream of objects of any type to a numeric stream. Please, notice that transformation (mapping) to a numeric type could be done using a generic map() too. But the output stream of values of type R (produced by Stream<R> object) will not have some of the operators specific to the numeric streams, like sum() or average(), for example.
The following are the code snippets that demonstrates map() usage:
Stream.of("two", "four", "three")
.map(s -> s.toUpperCase() + " ")
.forEach(System.out::print); //prints: TWO FOUR THREE
Stream.of("two", "four", "three")
.mapToInt(s -> s.length())
.mapToObj(i -> i + " ")
.forEach(System.out::print); //prints: 3 4 5
Stream.of("two", "four", "three")
.mapToLong(s -> s.length() * 2)
.mapToObj(l -> l + " ")
.forEach(System.out::print); //prints: 6 8 10
Stream.of("two", "four", "three")
.mapToDouble(s -> s.length() / 2.0)
.mapToObj(d -> d + " ")
.forEach(System.out::print); //prints: 1.5 2.0 2.5
The numeric streams provide specialized operations, like sum() or average(), for example. We will talk about the numeric stream in a dedicated post.
Please, notice that we use very simple functions for demonstration. In practice the mapping functions can contain many lines of code. For example:
Stream.of("two", "four", "three")
.map(s -> {
if(s.contains("o")){
return s.replace("o", "@");
} else {
return "*".repeat(s.length());
}
}
)
.map(s -> s + " ")
.forEach(System.out::print); //prints: tw@ f@ur *****
Embedded multi-line function maybe not easy to read, especially when there are many operators with such in-lin functions and each of them a dozen of more lines long. In such cases, one can implement each of the multi-line functions in a method. For example, in our case, we can write the following transformString() method:
private static String transformString(String s){
if(s.contains("o")){
return s.replace("o", "@");
} else {
return "*".repeat(s.length());
}
}
Then we can use this method as following:
Stream.of("two", "four", "three")
.map(s -> transformString(s))
.map(s -> s + " ")
.forEach(System.out::print); //prints: tw@ f@ur *****
This version of the same implementation is easier to read, isn’t it? If you are not familiar with functional programming and lambda expressions, in particular, we recommend you spending time and master these concepts. They are crucial for effective stream usage. You can read a brief introduction to these topics in our posts on functional programming and lambda expressions.
In the next post, we will talk about the last group of the–arguably the most powerful–intermediate operations flatMap() that create a new stream consisting of the results of replacing each element of the input stream with the elements of a new stream produced by applying the specified mapping function to each element.
See other posts on Java 8 streams and posts on other topics.
You can also use navigation pages for Java stream related blogs:
— Java 8 streams blog titles
— Create stream
— Stream operations
— Stream operation collect()
The source code of all the code examples is here in GitHub.
Send your comments using the link Contact or in response to my newsletter.
If you do not receive the newsletter, subscribe via link Subscribe under Contact.