Java 8 Stream API Example Tutorial
Stream API Overview
Before we look into Java 8 Stream API Examples, let’s see why it was required. Suppose we want to iterate over a list of integers and find out sum of all the integers greater than 10.
Prior to Java 8, the approach to do it would be:
1
2
3
4
5
6
7
8
9
10
11
|
private static int sumIterator(List<Integer> list) { Iterator<Integer> it = list.iterator(); int sum = 0 ; while (it.hasNext()) { int num = it.next(); if (num > 10 ) { sum += num; } } return sum; } |
There are three major problems with the above approach:
- We just want to know the sum of integers but we would also have to provide how the iteration will take place, this is also called external iteration because client program is handling the algorithm to iterate over the list.
- The program is sequential in nature, there is no way we can do this in parallel easily.
- There is a lot of code to do even a simple task.
To overcome all the above shortcomings, Java 8 introduces Stream API. We can use Stream API to implement internal iteration, that is better because java framework is in control of the iteration.
Internal iteration provides several features such as sequential and parallel execution, filtering based on the given criteria, mapping etc.
Most of the Stream API method arguments are functional interfaces, so lambda expressions work very well with them. Let’s see how can we write above logic in a single line statement.
1
2
3
|
private static int sumStream(List<Integer> list) { return list.stream().filter(i -> i > 10 ).mapToInt(i -> i).sum(); } |
Notice that above program utilizes java framework iteration strategy, filtering and mapping methods and would increase efficiency.
First of all we will look into the core concepts of Stream API and then we will go through some examples for understanding most commonly used methods.
Collections and Streams
A collection is an in-memory data structure to hold values and before we start using collection, all the values should have been populated. Whereas a Stream is a data structure that is computed on-demand.
Stream doesn’t store data, it operates on the source data structure (collection and array) and produce pipelined data that we can use and perform specific operations. Such as we can create a stream from the list and filter it based on a condition.
Stream operations use functional interfaces, that makes it a very good fit for functional programming using lambda expressions. As you can see in the above example that using lambda expressions make our code readable and short.
Stream internal iteration principle helps in achieving lazy-seeking in some of the stream operations. For example filtering, mapping, or duplicate removal can be implemented lazily, allowing higher performance and scope for optimization.
Streams are consumable, so there is no way to create a reference to stream for future usage. Since the data is on-demand, it’s not possible to reuse the same stream multiple times.
Stream support sequential as well as parallel processing, parallel processing can be very helpful in achieving high performance for large collections.
All the Stream API interfaces and classes are in the java.util.stream
package. Since we can use primitive data types such as int, long in the collections using auto-boxing and these operations could take a lot of time, there are specific classes for these – IntStream
, LongStream
and DoubleStream
.
Commonly used Functional Interfaces in Stream
Some of the commonly used functional interfaces in the Stream API methods are:
- Function and BiFunction: Function represents a function that takes one type of argument and returns another type of argument.
Function<t, r="">
is the generic form where T is the type of the input to the function and R is the type of the result of the function. For handling primitive types, there are specific Function interfaces –ToIntFunction
,ToLongFunction
,ToDoubleFunction
,ToIntBiFunction
,ToLongBiFunction
,ToDoubleBiFunction
,LongToIntFunction
,LongToDoubleFunction
,IntToLongFunction
,IntToDoubleFunction
etc.Some of the Stream methods where
Function
or it’s primitive specialization is used are:- <R> Stream<R> map(Function<? super T, ? extends R> mapper)
- IntStream mapToInt(ToIntFunction<? super T> mapper) – similarly for long and double returning primitive specific stream.
- IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper) – similarly for long and double
- <A> A[] toArray(IntFunction<A[]> generator)
- <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner)
- Predicate and BiPredicate: It represents a predicate against which elements of the stream are tested. This is used to filter elements from the stream. Just like
Function
, there are primitive specific interfaces for int, long and double.Some of the Stream methods where
Predicate
orBiPredicate
specializations are used are:- Stream<T> filter(Predicate<? super T> predicate)
- boolean anyMatch(Predicate<? super T> predicate)
- boolean allMatch(Predicate<? super T> predicate)
- boolean noneMatch(Predicate<? super T> predicate)
- Consumer and BiConsumer: It represents an operation that accepts a single input argument and returns no result. It can be used to perform some action on all the elements of the stream.
Some of the Stream methods where
Consumer
,BiConsumer
or it’s primitive specialization interfaces are used are:- Stream<T> peek(Consumer<? super T> action)
- void forEach(Consumer<? super T> action)
- void forEachOrdered(Consumer<? super T> action)
- Supplier: Supplier represent an operation through which we can generate new values in the stream. Some of the methods in Stream that takes
Supplier
argument are:- public static<T> Stream<T> generate(Supplier<T> s)
- <R> R collect(Supplier<R> supplier,BiConsumer<R, ? super T> accumulator,BiConsumer<R, R> combiner)
java.util.Optional
Optional is a container object which may or may not contain a non-null value. If a value is present,isPresent()
will return true and get()
will return the value. Stream terminal operations return Optional object. Some of these methods are:
- Optional<T> reduce(BinaryOperator<T> accumulator)
- Optional<T> min(Comparator<? super T> comparator)
- Optional<T> max(Comparator<? super T> comparator)
- Optional<T> findFirst()
- Optional<T> findAny()
java.util.Spliterator
For supporting parallel execution in Stream API, Spliterator
interface is used. Spliterator trySplit
method returns a new Spliterator that manages a subset of the elements of the original Spliterator.
Intermediate and Terminal Operations
Stream API operations that returns a new Stream are called intermediate operations. Most of the times, these operations are lazy in nature, so they start producing new stream elements and send it to the next operation. Intermediate operations are never the final result producing operations. Commonly used intermediate operations are filter
and map
.
Stream API operations that returns a result or produce a side effect. Once the terminal method is called on a stream, it consumes the stream and after that we can’t use stream. Terminal operations are eager in nature i.e they process all the elements in the stream before returning the result. Commonly used terminal methods are forEach
, toArray
, min
, max
, findFirst
, anyMatch
, allMatch
etc. You can identify terminal methods from the return type, they will never return a Stream.
Short Circuiting Operations
An intermediate operation is called short circuiting, if it may produce finite stream for an infinite stream. For example limit()
and skip()
are two short circuiting intermediate operations.
A terminal operation is called short circuiting, if it may terminate in finite time for infinite stream. For example anyMatch
, allMatch
, noneMatch
, findFirst
and findAny
are short circuiting terminal operations.
Java Stream Examples
I have covered almost all the important parts of the Java Stream API. It’s exciting to use this new API features and let’s see it in action with some examples.
Creating Streams
There are several ways through which we can create a stream from array and collections. Let’s look into these with simple examples.
- We can use
Stream.of()
to create a stream from similar type of data. For example, we can create Stream of integers from a group of int or Integer objects.1Stream<Integer> stream = Stream.of(
1
,
2
,
3
,
4
);
- We can use
Stream.of()
with an array of Objects to return the stream. Note that it doesn’t support autoboxing, so we can’t pass primitive type array.12345Stream<Integer> stream = Stream.of(
new
Integer[]{
1
,
2
,
3
,
4
});
//works fine
Stream<Integer> stream1 = Stream.of(
new
int
[]{
1
,
2
,
3
,
4
});
//Compile time error, Type mismatch: cannot convert from Stream<int[]> to Stream<Integer>
- We can use Collection
stream()
to create sequential stream andparallelStream()
to create parallel stream.12345678List<Integer> myList =
new
ArrayList<>();
for
(
int
i=
0
; i<
100
; i++) myList.add(i);
//sequential stream
Stream<Integer> sequentialStream = myList.stream();
//parallel stream
Stream<Integer> parallelStream = myList.parallelStream();
- We can use
Stream.generate()
andStream.iterate()
methods to create Stream.12Stream<String> stream1 = Stream.generate(() -> {
return
"abc"
;});
Stream<String> stream2 = Stream.iterate(
"abc"
, (i) -> i);
- Using
Arrays.stream()
andString.chars()
methods.12LongStream is = Arrays.stream(
new
long
[]{
1
,
2
,
3
,
4
});
IntStream is2 =
"abc"
.chars();
Converting Stream to Collection or Array
There are several ways through which we can get a Collection or Array from a Stream.
- We can use Stream
collect()
method to get List, Map or Set from stream.123456Stream<Integer> intStream = Stream.of(
1
,
2
,
3
,
4
);
List<Integer> intList = intStream.collect(Collectors.toList());
System.out.println(intList);
//prints [1, 2, 3, 4]
intStream = Stream.of(
1
,
2
,
3
,
4
);
//stream is closed, so we need to create it again
Map<Integer,Integer> intMap = intStream.collect(Collectors.toMap(i -> i, i -> i+
10
));
System.out.println(intMap);
//prints {1=11, 2=12, 3=13, 4=14}
- We can use stream
toArray()
method to create an array from the stream.123Stream<Integer> intStream = Stream.of(
1
,
2
,
3
,
4
);
Integer[] intArray = intStream.toArray(Integer[]::
new
);
System.out.println(Arrays.toString(intArray));
//prints [1, 2, 3, 4]
Stream Intermediate Operations
Let’s look into commonly used Stream intermediate operations example.
- Stream filter() example: We can use filter() method to test stream elements for a condition and generate filtered list.
1234567
List<Integer> myList =
new
ArrayList<>();
for
(
int
i=
0
; i<
100
; i++) myList.add(i);
Stream<Integer> sequentialStream = myList.stream();
Stream<Integer> highNums = sequentialStream.filter(p -> p >
90
);
//filter numbers greater than 90
System.out.print(
"High Nums greater than 90="
);
highNums.forEach(p -> System.out.print(p+
" "
));
//prints "High Nums greater than 90=91 92 93 94 95 96 97 98 99 "
- Stream map() example: We can use map() to apply functions to an stream. Let’s see how we can use it to apply upper case function to a list of Strings.
12345
Stream<String> names = Stream.of(
"aBc"
,
"d"
,
"ef"
);
System.out.println(names.map(s -> {
return
s.toUpperCase();
}).collect(Collectors.toList()));
//prints [ABC, D, EF]
- Stream sorted() example: We can use sorted() to sort the stream elements by passing Comparator argument.
1234567
Stream<String> names2 = Stream.of(
"aBc"
,
"d"
,
"ef"
,
"123456"
);
List<String> reverseSorted = names2.sorted(Comparator.reverseOrder()).collect(Collectors.toList());
System.out.println(reverseSorted);
// [ef, d, aBc, 123456]
Stream<String> names3 = Stream.of(
"aBc"
,
"d"
,
"ef"
,
"123456"
);
List<String> naturalSorted = names3.sorted().collect(Collectors.toList());
System.out.println(naturalSorted);
//[123456, aBc, d, ef]
- Stream flatMap() example: We can use flatMap() to create a stream from the stream of list. Let’s see a simple example to clear this doubt.
123456789
Stream<List<String>> namesOriginalList = Stream.of(
Arrays.asList(
"Pankaj"
),
Arrays.asList(
"David"
,
"Lisa"
),
Arrays.asList(
"Amit"
));
//flat the stream from List<String> to String stream
Stream<String> flatStream = namesOriginalList
.flatMap(strList -> strList.stream());
flatStream.forEach(System.out::println);
Stream Terminal Operations
Let’s look at some of the terminal operations example.
- Stream reduce() example: We can use reduce() to perform a reduction on the elements of the stream, using an associative accumulation function, and return an Optional. Let’s see how we can use it multiply the integers in a stream.
1234
Stream<Integer> numbers = Stream.of(
1
,
2
,
3
,
4
,
5
);
Optional<Integer> intOptional = numbers.reduce((i,j) -> {
return
i*j;});
if
(intOptional.isPresent()) System.out.println(
"Multiplication = "
+intOptional.get());
//120
- Stream count() example: We can use this terminal operation to count the number of items in the stream.
123
Stream<Integer> numbers1 = Stream.of(
1
,
2
,
3
,
4
,
5
);
System.out.println(
"Number of elements in stream="
+numbers1.count());
//5
- Stream forEach() example: This can be used for iterating over the stream. We can use this in place of iterator. Let’s see how to use it for printing all the elements of the stream.
12
Stream<Integer> numbers2 = Stream.of(
1
,
2
,
3
,
4
,
5
);
numbers2.forEach(i -> System.out.print(i+
","
));
//1,2,3,4,5,
- Stream match() examples: Let’s see some of the examples for matching methods in Stream API.
1234567891011
Stream<Integer> numbers3 = Stream.of(
1
,
2
,
3
,
4
,
5
);
System.out.println(
"Stream contains 4? "
+numbers3.anyMatch(i -> i==
4
));
//Stream contains 4? true
Stream<Integer> numbers4 = Stream.of(
1
,
2
,
3
,
4
,
5
);
System.out.println(
"Stream contains all elements less than 10? "
+numbers4.allMatch(i -> i<
10
));
//Stream contains all elements less than 10? true
Stream<Integer> numbers5 = Stream.of(
1
,
2
,
3
,
4
,
5
);
System.out.println(
"Stream doesn't contain 10? "
+numbers5.noneMatch(i -> i==
10
));
//Stream doesn't contain 10? true
- Stream findFirst() example: This is a short circuiting terminal operation, let’s see how we can use it to find the first string from a stream starting with D.
12345
Stream<String> names4 = Stream.of(
"Pankaj"
,
"Amit"
,
"David"
,
"Lisa"
);
Optional<String> firstNameWithD = names4.filter(i -> i.startsWith(
"D"
)).findFirst();
if
(firstNameWithD.isPresent()){
System.out.println(
"First Name starting with D="
+firstNameWithD.get());
//David
}
Java Stream API Limitations
Stream API brings a lot of new stuffs to work with list and arrays, but it has some limitations too.
- Stateless lambda expressions: If you are using parallel stream and lambda expressions are stateful, it can result in random responses. Let’s see it with a simple program.
StatefulParallelStream.java 1234567891011121314151617181920212223242526272829package
com.journaldev.java8.stream;
import
java.util.ArrayList;
import
java.util.Arrays;
import
java.util.List;
import
java.util.stream.Stream;
public
class
StatefulParallelStream {
public
static
void
main(String[] args) {
List<Integer> ss = Arrays.asList(
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
10
,
11
,
12
,
13
,
14
,
15
);
List<Integer> result =
new
ArrayList<Integer>();
Stream<Integer> stream = ss.parallelStream();
stream.map(s -> {
synchronized
(result) {
if
(result.size() <
10
) {
result.add(s);
}
}
return
s;
}).forEach( e -> {});
System.out.println(result);
}
}
If we run above program, you will get different results because it depends on the way stream is getting iterated and we don’t have any order defined for parallel processing. If we use sequential stream, then this problem will not arise.
- Once a Stream is consumed, it can’t be used later on. As you can see in above examples that every time I am creating a stream.
- There are a lot of methods in Stream API and the most confusing part is the overloaded methods. It makes the learning curve time taking.
That’s all for Stream API in Java. I am looking forward to use this feature and make the code readable with better performance through parallel processing.
Java 8 Stream API Example Tutorial的更多相关文章
- Java 8 Stream API详解--转
原文地址:http://blog.csdn.net/chszs/article/details/47038607 Java 8 Stream API详解 一.Stream API介绍 Java8引入了 ...
- Java 8 Stream API
Java 8 Stream API JDK8 中有两大最为重要的改变.第一个是 Lambda 式:另外 Stream API(java.util.stream.*) Stream 是 JDK8 中处理 ...
- Java 8 Stream API具体解释
Java 8 Stream API具体解释 一.Stream API介绍 Java 8引入了全新的Stream API,此Stream与Java I/O包里的InputStream和OutputStr ...
- Java 8 Stream Api 中的 peek 操作
1. 前言 我在Java8 Stream API 详细使用指南[1] 中讲述了 [Java 8 Stream API]( "Java 8 Stream API") 中 map 操作 ...
- Java 使用 Stream API 筛选 List
前言 上课的时候看到老师用迭代器来遍历 List 中的元素的时候,我的内心是极其嫌弃的,这种迭代方法不能直接访问当前的元素,而且写起来也麻烦.于是上网查了查 Java 有没有类似于 Linq 的东西, ...
- Java 8 Stream API的使用示例
前言 Java Stream API借助于Lambda表达式,为Collection操作提供了一个新的选择.如果使用得当,可以极大地提高编程效率和代码可读性. 本文将介绍Stream API包含的方法 ...
- Spring WebFlux 学习笔记 - (一) 前传:学习Java 8 Stream Api (3) - Stream的终端操作
Stream API Java8中有两大最为重要的改变:第一个是 Lambda 表达式:另外一个则是 Stream API(java.util.stream.*). Stream 是 Java8 中处 ...
- Spring WebFlux 学习笔记 - (一) 前传:学习Java 8 Stream Api (2) - Stream的中间操作
Stream API Java8中有两大最为重要的改变:第一个是 Lambda 表达式:另外一个则是 Stream API(java.util.stream.*). Stream 是 Java8 中处 ...
- Spring WebFlux 学习笔记 - (一) 前传:学习Java 8 Stream Api (1) - 创建 Stream
影子 在学习Spring WebFlux之前,我们先来了解JDK的Stream,虽然他们之间没有直接的关系,有趣的是 Spring Web Flux 基于 Reactive Stream,他们中都带了 ...
随机推荐
- leetcode@ [355] Design Twitter (Object Oriented Programming)
https://leetcode.com/problems/design-twitter/ Design a simplified version of Twitter where users can ...
- 在RHEL5.4 设置KVM(虚拟机)通过桥接器上网
以root身份登录系统,创建桥接器配置文件 #cd /etc/sysconfig/network-scripts/ #cp ifcfg-eth0 ifcfg-br0 #vi ifcfg-br0 桥接器 ...
- 现代程序设计——homework-07
1.写在前面 不得不很惭愧地说,在看这些博客之前,我对C++的了解仅限于上过一门特别水的关于C++的公选课.一门只有五节课的专业选修课,写过一点点符合C++语法语法规则的类C程序,偶尔在论坛.博客中看 ...
- Struts2在Action中访问WEB资源
什么是WEB资源? 这里所说的WEB资源是指:HttpServletRequest, HttpSession, ServletContext 等原生的 Servlet API. 为什么需要访问WEB资 ...
- JNI调用测试
有需求使用JNI调用,籍着这个机会按照<Linux下测试Java的JNI(Java Native Interface)>上进行了下测试. 这篇文章记录得很清楚了,对原理未做深入的分析,希望 ...
- HDU 4891 The Great Pan (模拟)
The Great Pan 题目链接: http://acm.hust.edu.cn/vjudge/contest/123554#problem/D Description As a programm ...
- [iOS微博项目 - 2.1] - 获得新浪授权接口
A.如何获得新浪的授权接口 登陆新浪的开放平台 注册新浪账号 创建应用 获得应用id和请求地址 查阅相关API 关联需要进行测试的账号 1.登陆开放平台 http://open.weibo.com ...
- ubuntu 如何在recovery模式修改root密码
今天遇到一个问题, 前提1: ubuntu系统的root密码我一直没有设定 前提2: ubuntu初始创建的sudo用户不知道怎么移除sudo权限用户了. 下面就精彩了, 首先没有root密码,你不 ...
- hdu 2553 N皇后问题 (经典DFS)
题目链接:点击链接 思路:用一维数组hang[num] = i,num表示第num行,i表示第i列,计算n = 1~10皇后的不同放置数量,然后打表 #include<stdio.h> # ...
- Eclipse添加小工具_打开当前文件所在文件夹
CopyRight yuhuashi http://www.cnblogs.com/chuyuhuashi/archive/2012/05/06/2485831.html 默认情况下使用eclip ...