Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。
Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作(bulk data operation)。
Stream API 借助于同样新出现的 Lambda 表达式,而且使用并发模式,极大的提高编程效率和程序可读性。
有下面的需求:
我们按照之前的原始方式编写代码如下:
public class StreamDemo {
public static void main(String[] args) {
//创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<String>();
list.add("赵丽颖");
list.add("玉如梦");
list.add("林若溪");
list.add("柳岩");
list.add("张晓龙");
list.add("张梦");
//把集合中所有以"张"开头的元素存储到一个新的集合
ArrayList<String> zhangList = new ArrayList<String>();
for(String s : list) {
if(s.startsWith("张")) {
zhangList.add(s);
}
}
// System.out.println(zhangList);
//把"张"开头的集合中的长度为3的元素存储到一个新的集合
ArrayList<String> threeList = new ArrayList<String>();
for(String s : zhangList) {
if(s.length() == 3) {
threeList.add(s);
}
}
// System.out.println(threeList);
//遍历上一步得到的集合
for(String s : threeList) {
System.out.println(s);
}
}
}
最后结果只有:张晓龙

我们使用Stream流修改这个代码如下:
public class StreamDemo {
public static void main(String[] args) {
//创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<String>();
list.add("赵丽颖");
list.add("玉如梦");
list.add("林若溪");
list.add("柳岩");
list.add("张晓龙");
list.add("张梦");
//Stream流来改进
list.stream().filter(s -> s.startsWith("张"))
.filter(s -> s.length() == 3)
.forEach(System.out::println);
// .forEach(item-> System.out.println(item));
}
}
运行结果一样

集合和流,同时承载一些表面的相似性,有不同的目标。集合主要关心的是有效的管理和访问他们的元素。相比之下,流不直接访问或操纵元素,它只是提供了一种手段,不关心声明的描述,不关心它们的来源,计算的操作将被执行在原数据中。
Stream操作需要三步,每一步及其相关操作过程如下:
| 三部曲 | 执行流程 |
|---|---|
| 生成Stream流 | 创建一条流水线,并把数据放到流水线上准备进行操作 |
| 中间方法 | 进行流水线上的操作 一次操作完毕之后,还可以继续进行其他操作 |
| 终结方法 | 一个Stream流只能有一个终结方法 是流水线上的最后一个操作 |
Stream流的思想:获取方法获得数据流,中间方法一步步的操作数据流,终结方法最终输出数据流

下面我们来详细介绍一下每个方法
Collection体系集合可以使用默认方法stream()生成流:
default Stream<E> stream()
例如,List生成流:
List<String> list = new ArrayList<String>();
Stream<String> listStream = list.stream();
有两种方法:
方法一:Map体系集合需要把Map转成Set集合,需要间接的生成流,具体步骤是先将key与value单独的生成流,再合并
例如:
Map<String,Integer> map = new HashMap<String, Integer>();
Stream<String> keyStream = map.keySet().stream();
Stream<Integer> valueStream = map.values().stream();
Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
方法二: 通过Map.Entry 直接的生成流
例如:
Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
通过Arrays中的静态方法stream生成流
语法如下:
Arrays.stream(数组);
通过Stream接口的静态方法of(T… values)生成流
语法如下:
Stream.of(T... values)
例如:
Stream<Integer> intStream = Stream.of(10, 20, 30);
代码如下:
package com.test;
import java.util.*;
import java.util.stream.Stream;
public class StreamDemo {
public static void main(String[] args) {
//Collection体系的集合可以使用默认方法stream()生成流
System.out.println("Collection体系的集合=============================");
List<String> list = new ArrayList<String>();
list.add("苏映雪");
list.add("玉如梦");
Stream<String> listStream = list.stream();
listStream.filter(s -> s.endsWith("梦"))
.forEach(s -> System.out.println(s));
Set<String> set = new HashSet<>();
Stream<String> setStream = set.stream();
// Map体系的集合间接的生成流
System.out.println("Map体系的集合=============================");
Map<String,Integer> map = new HashMap<String, Integer>();
map.put("玉如梦",325);
map.put("岁月枯荣",23);
map.put("如梭如梦",18);
Stream<String> keyStream = map.keySet().stream();
Stream<Integer> valueStream = map.values().stream();
keyStream.filter(s -> s.contains("如梦"))
.forEach(s -> System.out.println(s));
valueStream.filter(s -> s>100)
.forEach(s -> System.out.println(s));
// Map体系的集合直接的生成流
Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
entryStream.filter( stringIntegerEntry -> {
boolean a = stringIntegerEntry.getKey().contains("玉如梦");
boolean b = stringIntegerEntry.getValue()>200;
return a&&b;
}).forEach(stringIntegerEntry -> {
System.out.println("天之娇女:"+stringIntegerEntry.getKey()+" "+stringIntegerEntry.getValue()+"岁");
});
//数组可以通过Arrays中的静态方法stream生成流
System.out.println("数组=============================");
String[] strArray = {"hello","world","java"};
Stream<String> strArrayStream = Arrays.stream(strArray);
strArrayStream.filter(s -> s.contains("o")).forEach(s -> System.out.println(s));
//同种数据类型的多个数据可以通过Stream接口的静态方法of(T... values)生成流
System.out.println("同种数据类型的多个数据=============================");
Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");
Stream<Integer> intStream = Stream.of(10, 20, 30);
intStream.filter(integer -> integer>15).forEach(integer -> System.out.println(integer.toString()+","));
}
}
运行结果如下:

概念
常见方法
| 方法名 | 说明 |
|---|---|
| Stream filter(Predicate predicate) | 用于对流中的数据进行过滤 |
| Stream limit(long maxSize) | 返回此流中的元素组成的流,截取 前指定参数(maxSize)个 数的数据 |
| Stream skip(long n) | 跳过指定参数个数的数据,返回由该流的剩余元素组成的流 |
| static Stream concat(Stream a, Stream b) | 合并a和b两个流为一个流 |
| Stream distinct() | 返回由该流的不同元素(根据Object.equals(Object) )组成的流 |
public class StreamDemo {
public static void main(String[] args) {
//创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<String>();
list.add("赵丽颖");
list.add("玉如梦");
list.add("林若溪");
list.add("柳岩");
list.add("如梦");
list.add("张无忌");
//需求1:把list集合中以张开头的元素在控制台输出
list.stream().filter(s -> s.startsWith("张")).forEach(System.out::println);
System.out.println("==============================");
//需求2:把list集合中长度为3的元素在控制台输出
list.stream().filter(s -> s.length() == 3).forEach(System.out::println);
System.out.println("==============================");
//需求3:把list集合中以张开头的,长度为3的元素在控制台输出
list.stream().filter(s -> s.contains("如梦")).filter(s -> s.length() == 3).forEach(System.out::println);
}
}

public class StreamDemo {
public static void main(String[] args) {
//创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<String>();
list.add("赵丽颖");
list.add("玉如梦");
list.add("林若溪");
list.add("柳岩");
list.add("如梦");
list.add("张无忌");
Stream<String> listStream = list.stream();
//需求1:取前3个数据在控制台输出
listStream.limit(3).forEach(System.out::println);
System.out.println("==============================");
//需求2:跳过3个元素,把剩下的元素在控制台输出
listStream.skip(3).forEach(System.out::println);
System.out.println("==============================");
//需求3:跳过2个元素,把剩下的元素中前2个在控制台输出
listStream.skip(2).limit(2).forEach(System.out::println);
}
}
运行结果如下:

public class StreamDemo {
public static void main(String[] args) {
//创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<String>();
list.add("赵丽颖");
list.add("玉如梦");
list.add("林若溪");
list.add("柳岩");
list.add("玉如梦");
list.add("林若溪");
//需求1:取前4个数据组成一个流
Stream<String> s1 = list.stream().limit(4);
//需求2:跳过2个数据组成一个流
Stream<String> s2 = list.stream().skip(2);
//需求3:合并需求1和需求2得到的流,并把结果在控制台输出
// Stream.concat(s1,s2).forEach(System.out::println);
//需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复
Stream.concat(s1,s2).distinct().forEach(System.out::println);
}
}
运行结果如下:

概念
常见方法
| 方法名 | 说明 |
|---|---|
| void forEach(Consumer action) | 对此流的每个元素执行操作 |
| long count() | 返回此流中的元素数 |
public class StreamDemo {
public static void main(String[] args) {
//创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<String>();
list.add("赵丽颖");
list.add("玉如梦");
list.add("林若溪");
list.add("玉晴儿");
list.add("曲华裳");
list.add("张晓婷");
//需求1:把集合中的元素在控制台输出
list.stream().forEach(System.out::println);
//需求2:统计集合中有几个以张开头的元素,并把统计结果在控制台输出
long count = list.stream().filter(s -> s.startsWith("玉")).count();
System.out.println(count);
}
}
运行结果如下:

概念
常用方法
| 方法名 | 说明 |
|---|---|
| R collect(Collector collector) | 把结果收集到集合中 |
同时工具类Collectors提供了具体的收集方式
| 方法名 | 说明 |
|---|---|
| public static Collector toList() | 把元素收集到List集合中 |
| public static Collector toSet() | 把元素收集到Set集合中 |
| public static Collector toMap(Function keyMapper,Function valueMapper) | 把元素收集到Map集合中 |
public class CollectDemo {
public static void main(String[] args) {
//创建List集合对象
System.out.println("List集合收集操作============================");
List<String> list = new ArrayList<String>();
list.add("玉如梦");
list.add("林若溪");
list.add("曲华裳");
list.add("祝晴");
Stream<String> listStream = list.stream().filter(s -> s.length() == 3);
List<String> names = listStream.collect(Collectors.toList());
for (String name : names) {
System.out.println(name);
}
//创建Set集合对象
System.out.println("Set集合收集操作============================");
Set<Integer> set = new HashSet<Integer>();
set.add(10);
set.add(20);
set.add(30);
set.add(33);
set.add(35);
// 得到年龄大于25的流
Stream<Integer> setStream = set.stream().filter(age -> age > 25);
// 把使用Stream流操作完毕的数据收集到Set集合中并遍历
Set<Integer> ages = setStream.collect(Collectors.toSet());
for (Integer age : ages) {
System.out.println(age);
}
// 定义一个字符串数组,每一个字符串数据由姓名数据和年龄数据组合而成
System.out.println("Map集合收集操作============================");
String[] strArray = {"曲华裳,30", "玉如梦,35", "林若溪,33", "祝晴,25"};
// 得到字符串中年龄数据大于28的流
Stream<String> arrayStream = Stream.of(strArray)
.filter(s -> Integer.parseInt(s.split(",")[1]) > 28);
// 把使用Stream流操作完毕的数据收集到Map集合中并遍历,字符串中的姓名作键,年龄作值
Map<String, Integer> map = arrayStream.collect(Collectors.toMap(s -> s.split(",")[0], s -> Integer.parseInt(s.split(",")[1])));
Set<String> keySet = map.keySet();
for (String key : keySet) {
Integer value = map.get(key);
System.out.println(key + "," + value);
}
}
}
运行结果如下:
