Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
但请注意区别于我们的io流,Java中的Stream并不会存储元素,而是按需计算。
外部迭代是一个串行的操作,如果数据量过大,性能可能会受影响,这样我们可能就需要自己去做线程池,做拆分。内部迭代的话可以用并行流,达到并行操作,不用开发人员去关系线程的问题。
Stream 中调用后返回stream流的方法,都是属于中间操作。
终止操作返回的是一个结果,就是所有中间操作做完以后进行的一个操作,比如汇总,求和,遍历输出等等操作。
不进行终止操作的情况下,中间操作不会执行。
方法 | 说明 |
---|---|
map / mapToObj / mapToLong / mapToDouble | 将流中的元素映射成另外一种元素 |
floatMap / flatMapToInt / flatMapToLong / flatMapToDouble | 类似于笛卡尔积的映射 |
filter | 对流中的元素进行过滤操作 |
peek | 获取元素,但不能对元素进行修改 |
unordered | 返回无序流 |
distinct | 去重 |
sorted | 排序 |
limit | 限制个数 |
skip | 跳过个数 |
@Test
public void demo2(){
List<String> list = Arrays.asList("1","2","3");
// map 的参数Function 是 T -> R (理解为单纯的转换类型)
list.stream().map(Long::parseLong).forEach(System.out::println);
System.out.println("============================================");
// flatMap 的参数Function 是 T -> Stream(理解为元素与另一个Stream对应并转换为Stream)
list.stream().flatMap(t -> list.stream().map(k -> t + ":"+k)).forEach(System.out::println);
}
1
2
3
============================================
1:1
1:2
1:3
2:1
2:2
2:3
3:1
3:2
3:3
@Test
public void demo3(){
// filter 接收一个 Predicate ,用于判断,返回满足要求的 Stream
Stream.of(1,2,3,4,5,7,8).filter(t -> t > 5).forEach(System.out::println);
System.out.println("============================================");
// 比如我们将 flatMap 的结果,过滤为 元素值相对应的结果
Stream.of(1,2,3,4,5,7,8)
.flatMap(t -> Stream.of(1,2,3,4,5,7,8,0)
.filter(n -> n == t)
.map(k -> t + ":"+k))
.forEach(System.out::println);
}
7
8
============================================
1:1
2:2
3:3
4:4
5:5
7:7
8:8
@Test
public void demo4(){
Stream.of(1,2,3,4,5,7,8)
// peek 接收 Consumer,意味着它不能修改元素的值
.peek(System.out::println)
.map(t -> t * t)
.peek(System.out::println)
// peek是中间操作,不会执行,需要执行结束操作才会执行
.forEach(System.out::println);
}
1
1
1
2
4
4
3
9
9
4
16
16
5
25
25
7
49
49
8
64
64
peek无法修改元素的值,那么它到底有什么作用呢,如同我们的打印结果一样,我们的第二个peek打印的是经过map后的元素的值,当我们中间操作特别多的时候,我们可以利用peek来验证得到的值是否符合我们的要求。
从打印的结果,我们还可以得到一个结论,那就是元素是一个一个的经过Stream的操作的,不是整体执行的。
@Test
public void demo5(){
Stream.of(1,2,3,4,5,7,8)
// 返回一个无序流,可能返回自身,以让后续的操作可以不考虑顺序,可提高并行执行的性能
.unordered()
.forEach(System.out::println);
System.out.println("=====================");
Stream.of(1,2,3,4,5,7,8)
.unordered()
.parallel()
.forEach(System.out::println);
}
@Test
public void demo6(){
Stream.of(1,2,3,6,8,4,5,7,8,1,4)
// 去重
.distinct()
// 排序
.sorted()
// 剩下的取 5条
.limit(5)
// 剩下的跳过 2 条
.skip(2)
.forEach(System.out::println);
System.out.println("========================");
Stream.of(1,2,3,6,8,4,5,7,8,1,4)
// 剩下的取 5条
.limit(5)
// 去重
.distinct()
// 排序
.sorted()
// 剩下的跳过 2 条
.skip(2)
.forEach(System.out::println);
}
3
4
5
========================
3
6
8
方法 | 说明 |
---|---|
forEach / forEachOrdered | 遍历元素 |
toArray / collect | 元素汇聚(汇聚成数组或集合) |
reduce | 递归计算 |
min / max / count / sum / average | 最大/最小/元素个数/求和/求平均 |
findFirst / findAny | 查找第一个 / 查找任意一个 |
anyMatch / allMatch / noneMatch | 至少一个满足 / 全部满足 / 全部不满足 |
@Test
public void demo8(){
// 直接转换为 List
List<Integer> list = Stream.of(1,8,2,7,8,3,5,3,5,2,4).collect(Collectors.toList());
System.out.println(list);
System.out.println("===========================");
// 收集为 Set (可达到去重效果)
Set<Integer> set = Stream.of(1,8,2,7,8,3,5,3,5,2,4).collect(Collectors.toSet());
System.out.println(set);
System.out.println("===========================");
// 收集为 Set (可达到去重效果)
Set<Integer> hashSet = Stream.of(1,8,2,7,8,3,5,3,5,2,4).collect(Collectors.toCollection(HashSet::new));
System.out.println(hashSet);
System.out.println("===========================");
}
@Test
public void demo9(){
// 本示例用于将对象列表转换为Map,使用id为Key,对象本身为value
Map<Long,User> map = Stream.of(new User(1L,"张飞",18),
new User(2L,"关羽",20),
new User(3L,"刘备",22),
new User(4L,"诸葛亮",10),
new User(5L,"曹操",36),
new User(6L,"孙权",12),
new User(7L,"张辽",19))
// Collectors.toMap 前两个参数都是Function,用于定义map的key和value
.collect(Collectors.toMap(User::getId, user -> user));
System.out.println(map);
}
@Test
public void demo10(){
// 本示例用于将对象列表转换为Map,使用id为Key,对象本身为value
Map<Boolean, List<User>> map = Stream.of(new User(1L,"张飞",18),
new User(2L,"关羽",20),
new User(3L,"刘备",22),
new User(4L,"诸葛亮",10),
new User(5L,"曹操",36),
new User(6L,"孙权",12),
new User(7L,"张辽",19))
// 年龄大于20的为一组,小于等于20的为一组
.collect(Collectors.partitioningBy(user -> user.getAge() > 20));
System.out.println(map);
}
@Test
public void demo11(){
// 本示例用于将对象列表转换为Map,使用id为Key,对象本身为value
Map<String, List<User>> map = Stream.of(new User(1L,"张飞",18,"蜀国"),
new User(2L,"关羽",20,"蜀国"),
new User(3L,"刘备",22,"蜀国"),
new User(4L,"诸葛亮",10,"蜀国"),
new User(5L,"曹操",36,"魏国"),
new User(6L,"孙权",12,"吴国"),
new User(7L,"张辽",19,"魏国"))
// 按阵营分组 groupingBy
.collect(Collectors.groupingBy(User::getCountry));
System.out.println(map);
}
@Test
public void demo7(){
// 返回一个 Optional
Optional<Integer> rs = Stream.of(1,2,3,4)
// 接收一个 BinaryOperator , BinaryOperator 继承自 BiFunction
// BiFunction 的函数式方法为:R apply(T t, U u);类似于Function只不过它是将T和U进行运算后得到R
.reduce(Integer::sum);
System.out.println(rs.get());
System.out.println("==============================");
// 返回具体的类型
int rs1 = Stream.of(1,2,3,4)
// identity 表示结果的初始值 (类似于我们常规写法求和时会先定义一个 int sum = 0)
// 接收一个 BinaryOperator , BinaryOperator 继承自 BiFunction
// BiFunction 的函数式方法为:R apply(T t, U u);类似于Function只不过它是将T和U进行运算后得到R
.reduce(0,Integer::sum);
System.out.println(rs1);
System.out.println("==============================");
long count1 = Stream.of(1,2,3,4).count();
long count2 = IntStream.of(1,2,3,4).count();
System.out.println("count1:" + count1 + ";count2:" + count2);
System.out.println("==============================");
// 注意如下两种写法的区别(max同理,这里就不做示例了)
Optional<Integer> min1 = Stream.of(1,2,3,4).min(Integer::compare);
OptionalInt min2 = IntStream.of(1,2,3,4).min();
System.out.println("min1:" + min1.get() + ";min2:" + min2.getAsInt());
System.out.println("==============================");
// 注意:sum和average只有数字类的Stream才有此方法
int sum = IntStream.of(1,2,3,4).sum();
OptionalDouble avg = IntStream.of(1,2,3,4).average();
System.out.println("sum:" + sum + ";avg:" + avg.getAsDouble());
}