前言
java8的新特性,允许开发人员以声明式方式处理集合,Stream并不是同集合数组这样的一种数据结构,可以将其理解成某种数据源的一个视图,这种数据源可是集合、数组、I/O和channel等。
一、Stream流的创建
集合数组等都可以转换成Stream流,例如:
@Test
public void createTest(){
//集合的Stream方法--------------------------------------------------------------------
List<String> list = Arrays.asList("a", "b");
Stream<String> stream = list.stream();
//并行流:list.parallelStream();
//map集合可以获取Entry, key 及 value的stream流
Map<String,String> map = new HashMap<>();
map.entrySet().stream();
map.keySet().stream();
map.values().stream();
//数组工具类的Stream方法----------------------------------------------------------------
String[] arr = {"c", "d"};
Stream<String> stream1 = Arrays.stream(arr);
//并行流:Arrays.stream(arr).parallel();
//Stream的静态方法---------------------------------------------------------------------
Stream<String> stream2 = Stream.of("e", "f");
Stream<Object> empty = Stream.empty();
//生成一个无限流,接收一个种子值和一个迭代函数(增长)
Stream.iterate(0, s -> s + 1).limit(10);//0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
//generate(Supplier<T> s) 生成一个无限流,元素由供给者Supplier产生,
Stream.generate(Math::random).limit(5);
//连接两个流 concat
Stream<String> concat = Stream.concat(stream, stream1);
}
二、Stream流中常用方法
Stream类中的每一个方法都对应集合上的一种操作,通过Lamada表达式将函数式编程引入java中,使代码更简洁,极大的简化了集合的处理操作。
- 中间操作:每次操作返回一个流,可以进行多次中间操作
无状态操作:可以直接对单个元素进行的操作,不受之前操作元素的影响;
有状态操作:只有获取到所有元素后才能执行的操作。 - 终端操作:每个流只能进行一个终端操作,执行后流无法再次使用,返回一个新的集合或者对象。
非短路操作:必须处理所有元素才能得到最终结果;
短路操作:遇到某些符合条件的元素就可以得到最终结果。
1、中间操作 - 无状态操作
可以直接对单个元素进行的操作,不受之前操作元素的影响
- 筛选
filter:filter(Predicate<? super T> predicate);
入参为断言型接口,根据给定的条件过滤流中的某些元素。
distinct:Stream<T> distinct();
通过流中元素的 hashCode() 和 equals() 方法去除重复元素。
public static List<Integer> TEST_LIST = Arrays.asList(10,20,14,15,20,30,10,8,25,20,30);
@Test
public void test(){
//20, 20, 30, 25, 20, 30,
TEST_LIST.stream().filter(s -> s > 15).forEach(str -> System.out.print(str + ", "));
//10, 20, 14, 15, 30, 8, 25,
TEST_LIST.stream().distinct().forEach(str -> System.out.print(str + ", "));
}
- 切片
limit(n):limit(long maxSize);
获取 n 个元素。
skip(n):skip(long n);
跳过 n 个元素,可以与 limit 配合实现分页。
@Test
public void test1(){
//10, 20, 14, 15, 20,
TEST_LIST.stream().limit(5).forEach(str -> System.out.print(str + ", "));
//30, 10, 8, 25, 20, 30,
TEST_LIST.stream().skip(5).forEach(str -> System.out.print(str + ", "));
}
- 映射:将一个流的元素按照给定的规则映射到另一个流中。
map:map(Function<? super T, ? extends R> mapper);
接收一个函数型接口作为参数,该接口实现方法会应用到每个元素上,将其映射成一个新的元素。
flatMap:flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
接收一个函数型接口作为参数,参数T转换成R(Stream流),将流中的每个元素都转换成另一流,然后把所有的流连接成一个新的流返回。
mapToInt:mapToInt(ToIntFunction<? super T> mapper);
接收一个函数型接口参数,返回一个Int元素的Stream流
flatMapToInt:flatMapToInt(Function<? super T, ? extends IntStream> mapper);
函数型接口参数,R为IntStream,返回一个操作Int的IntStream流。
@Test
public void test2(){
//10F, 20F, 14F, 15F, 20F, 30F, 10F, 8F, 25F, 20F, 30F,
TEST_LIST.stream().map(str -> str + "F").forEach(s -> System.out.print(s + ", "));
//1, 0, 2, 0, 1, 4, 1, 5, 2, 0, 3, 0, 1, 0, 8, 2, 5, 2, 0, 3, 0,
TEST_LIST.stream()
.map(String::valueOf)
//如元素10 拆成1 和 0 组成的流
.flatMap(str -> {
String[] split = str.split("");
return Arrays.stream(split);
}).forEach(s -> System.out.print(s + ", "));
//2, 1, 3,
Arrays.asList("aa","b","ccc").stream()
.mapToInt(String::length)
.forEach(s -> System.out.print(s + ", "));
//3, 2, 4,
Arrays.asList("aa","b","ccc").stream()
.flatMapToInt(str->IntStream.of(str.length()+1))
.forEach(s-> System.out.print(s + ", "));
}
- 消费
peek:peek(Consumer<? super T> action);
对流中的每个元素进行操作。与 map 类似,但 map 接收一个 Function 表达式,有返回值;而 peek 接收的是一个 Consumer 表达式,没有返回值,可能会修改流中元素的初始数据值。
@Test
public void test3(){
StringBuilder[] sbs = {new StringBuilder("a"),new StringBuilder("B")};
//[a, B]
System.out.println(Arrays.toString(sbs));
//a11, B11,
Arrays.stream(sbs).peek(sb -> sb.append("11")).forEach(s -> System.out.print(s + ", "));
//[a11, B11] peek作为消费者,可能会改变原来对象值
System.out.println(Arrays.toString(sbs));
}
2、中间操作 - 有状态操作
只有获取到所有元素后才能执行的操作
- 排序
sorted:sorted();
自然排序,流中的元素需要实现Comparable接口。
sorted:sorted(Comparator<? super T> comparator);
自定义排序,自定义Comparator比较器。
@Test
public void test4(){
//aaa, aba, ba, bc, c,
Arrays.asList("aba","aaa","bc","ba","c").stream()
.sorted()
.forEach(s-> System.out.print(s + ", "));
//c,bc,ba,aba,aaa,
Arrays.asList("aba","aaa","bc","ba","c").stream()
.sorted(Comparator.comparingInt(String::length))
.forEach(s-> System.out.print(s + ","));
}
3、终端操作 - 短路操作
遇到某些符合条件的元素就可以得到最终结果
- 判断
allMatch:allMatch(Predicate<? super T> predicate);
接收一个Predicate参数,当流中每个元素都满足表达式的条件时返回 true,否则返回 false。相当于 =all
noneMatch:noneMatch(Predicate<? super T> predicate);
接收一个Predicate参数,当流中的每个元素都不满足表达式的条件时返回 true,否则返回 false。相当于 not in
anyMatch:anyMatch(Predicate<? super T> predicate);
接收一个Predicate参数,当流中出现某一个元素满足表达式的条件时返回 true,否则返回 false。相当于 =any ( in )
@Test
public void test5(){
List<String> list = Arrays.asList("aa", "b", "ccc");
//都满足 长度大于2
boolean allMatch = list.stream().allMatch(str -> str.length() > 2); //false
//都不满足 为null
boolean noneMatch = list.stream().noneMatch(String::isEmpty); //true
//任意一个满足 包含c
boolean anyMatch = list.stream().anyMatch(str -> str.contains("c")); //true
}
- 获取
findFirst:Optional<T> findFirst();
返回流中的第一个元素。
findAny:Optional<T> findAny();
返回流中的任意一个元素。
@Test
public void test6(){
List<String> list = Arrays.asList("aa", "c", "d","a","b");
Optional<String> first = list.stream().findFirst();
System.out.println(first.get()); //aa
Optional<String> any = list.stream().findAny();
System.out.println(any.get()); //aa
}
4、终端操作 - 非短路操作
必须处理所有元素才能得到最终结果
主要进行一些对结果进行聚合、规约或者收集等操作
- 聚合
count:long count();
返回流中元素的总数。
max:Optional<T> max(Comparator<? super T> comparator);
返回流中元素的最大值。
min:Optional<T> min(Comparator<? super T> comparator);
返回流中元素的最小值。
@Test
public void test7(){
List<String> list = Arrays.asList("7", "3", "4","1","2");
long count = list.stream().filter(s->Integer.parseInt(s) > 3).count();
System.out.println(count);//2
Optional<String> max = list.stream().max(String::compareTo);
System.out.println(max.get());//7
Optional<String> min = list.stream().min(String::compareTo);
System.out.println(min.get());//1
}
- 收集:收集一个 Collector 实例,将流中返回的元素收集成另外一个数据结构。
通过Collectors工具对像中的方法:
toList()
toSet()
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper)
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction)
(BinaryOperator extends BiFunction<T,T,T>)
joining(CharSequence delimiter)
@Test
public void test8(){
String[] arr = new String[]{"a","bb","ccc","d"};
//转换成List
List<String> list = Arrays.stream(arr).collect(Collectors.toList());
System.out.println(list); //[a, bb, ccc, d]
//转换成Set
Set<Integer> set = Arrays.stream(arr).map(String::length).collect(Collectors.toSet());
System.out.println(set); //[1, 2, 3]
//转换成Map,保证key唯一,否则报错
Map<String, Integer> map = Arrays.stream(arr).collect(Collectors.toMap(Function.identity(), String::length));
System.out.println(map); //{bb=2, a=1, ccc=3, d=1}
//转换成Map,key重复,自定义策略,(o,o1)->o1:原来值为o,现在值为o1,取o1,即新值覆盖
Map<Integer, String> map1 = Arrays.stream(arr)
.collect(Collectors.toMap(String::length, Function.identity(),(o,o1)->o1));
System.out.println(map1); //{1=d, 2=bb, 3=ccc}
//转String,joining加入分隔符
String collect = Arrays.stream(arr).collect(Collectors.joining(","));
System.out.println(collect); //a,bb,ccc,d
}
- 归约:reduce 将流中的元素缩减成一个值进行返回,通常用于求和、求积等操作。
public void test11(){
List<Integer> list = Arrays.asList(1, 2, 3);
Optional<Integer> reduce = list.stream().reduce(Integer::sum);
System.out.println(reduce.get()); //6
//两个参数的 第一个参数其实就是累加对象参数的初始值(必须是流元素类型)
Integer sum = list.stream().reduce(10, Integer::sum);
System.out.println(sum); //16
//三个参数的
Integer reduce1 = list.stream().reduce(10, (x, y) -> x + y, (x, y) -> x + y);
System.out.println(reduce1); //16
//(10+1) +2 + 3
Integer reduce2 = list.parallelStream().reduce(10, (x, y) -> x + y, (x, y) -> x + y);
//10 + 1 + 10+ 2 + 10+3
System.out.println(reduce2); //36
}
对于规约方法reduce的三个参数的详解见:https://blog.youkuaiyun.com/qq_43621307/article/details/128407863
文章参考:
https://blog.youkuaiyun.com/ss810540895/article/details/126172285
https://blog.youkuaiyun.com/sinat_36645384/article/details/121494363