java8 Stream API
程序员文章站
2022-05-28 11:36:49
...
java8 Stream API
一. Stream API 概述
jva8在java.util.stream包下,通过Stream真正的引入函数式编程,可以对数据进行复杂的查找,过滤映射,提供了高效且易于使用的处理数据的方式,例如想要获取集合中的某些特定元素,在以前需要遍历集合,对每个元素进行筛选代码比较多,通过Stream,一行代码就可以搞定
- Stream 不会存储元素
- Stream 不会改变源对象,会返回一个持有结果的心的Stream
- Stream 是延迟执行的(创建一个有数据的Stream元数据流–>通过Stream对数据进行处理–>终止操作产生结果,只有调用终止操作以后前面的计算才会执行,否则算调用计算的方法,不执行的,终止后的Stream不可以再次继续进行中间处理,若想处理重新获取流,或一次性执行中间处理完毕后再调用终止)
二. Stream实例化方式
- 通过集合调用stream()方法获取Stream顺序流
- 通过集合调用parallelStream()方法获取Stream并行流
- 通过数组获取Stream
- 无限流
创建Stream流的方式代码示例
@Test
public void test1(){
//创建Stream的方式
List<Persion> persionList = new ArrayList<>();
persionList.add(new Persion("小明",22,2000.00));
persionList.add(new Persion("小红",34,2500.00));
persionList.add(new Persion("AA",18,1800.00));
persionList.add(new Persion("小强",40,3500.00));
persionList.add(new Persion("小黑",22,2200.00));
persionList.add(new Persion("小花",27,2000.00));
persionList.add(new Persion("bb",16,1500.00));
//1.通过集合中的.stream()获取Stream流,注意该方法返回的是一个顺序流(根据向集合中添加的顺序)
Stream<Persion> stream1 = persionList.stream();
//通过集合中的parallelStream()获取一个并行流,有点像通过几个线程同时去取,顺序可能发生改变
Stream<Persion> stream2 = persionList.parallelStream();
//2.通过Arrays工具类中的stream(T[] array)静态方法获取Stream流
//集合转数组
Persion[] perArray = persionList.toArray(new Persion[persionList.size()]);
Stream<Persion> stream = Arrays.stream(perArray);
//注意点,在使用Arrays中的stream()方法获取Stream流时,根据像方法中传递的
//泛型T不同,其返回的Stream不同
int[] iArray = new int[]{1,4,9};
long[] lArray = new long[]{11l,22l,6l};
double[] dArray = new double[]{7.8,14.3,5.1};
IntStream intStream = Arrays.stream(iArray);
LongStream longStream = Arrays.stream(lArray);
DoubleStream doubleStream = Arrays.stream(dArray);
//3.通过Stream的of()方法创建,将数据传入of()方法中
Stream<Integer> stream3 = Stream.of(1, 2, 3, 4);
//4.创建无限Stream流,输出0-10的偶数,
//iterate()中0代表开始位置,后面的Lambda传递的是Function<T,T> +2返回
//limit为中止操作,10
//forEach()为执行体
Stream.iterate(0,t -> t +2).limit(10).forEach(System.out :: println);
//生成,获取10个随机数
Stream.generate(Math :: random).limit(10).forEach(System.out :: println);
}
三. Stream 中间操作(通过Stream操作数据)
概述
使用Stream对数据继续操作,例如过滤筛选,映射,排序等,注意点: Stream被称为"惰性求值",在进行中间操作时,如果最终不调用终止,则中间操作无效,在调用终止操作后,若有后续的操作需要重新获取Stream流,否则无效
1. 筛选切片
1)方法概述
2)代码示例
@Test
public void test1(){
//persionList是一个List<Persion>集合
//获取Stream流
Stream<Persion> stream = persionList.stream();
//筛选与切片
//1.filter(Predicate p) 过滤,接收 Lambda ,从流中排除某些元素
//获取集合中age大于20的数据
stream.filter(p -> p.getAge()>20).forEach(System.out :: println);
//2.limit(n) 截断流,使其元素不超过给定的数量n
Stream<Persion> stream2 = persionList.stream();
//获取集合中前三条数据
stream2.limit(3).forEach(System.out :: println);
//3.skip(n) 跳过元素,返回一个不包括n以前个数的元素,若流中不足n个数据则返回就返回一个空流
//去掉集合中前3个元素
persionList.stream().skip(3).forEach(System.out :: println);
//4.distinct() 筛选,通过流所生成元素的hashCode()和equals()去除重复元素
//去重
persionList.stream().distinct().forEach(System.out :: println);
}
2. 映射
1)方法概述
2)代码示例
@Test
public void test2(){
//1.map(Function f) 接收一个函数作为参数,将元素映射成其它形式或获取信息,
//该函数会被应用到每个元素上,并将其映射到新的元素
//map()会依次对Stream中的每个元素执行
//示例1,将集合中所有字符串转换为大写
List<String> stringList = Arrays.asList("aa", "bb", "cc");
stringList.stream().map(str -> str.toUpperCase()).forEach(System.out :: println);
//示例2,获取集合姓名包含"小"的员工的姓名
Stream<String> ageStream = persionList.stream().map(Persion::getName);
ageStream.filter(name -> name.contains("小")).forEach(System.out :: println);
//2.flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流
//然后把所有流连接成一个流,与map()方法的区别有点像集合中的add(),与addAll()
//假设调用add方法向集合中添加另外一个集合是会变成[obj1, obj2, obj3,List[obj1,obj2,obj3]]
//如果调用addAll(),则会重新组合为一个集合,而不是集合作为集合类型元素存在
//假设通过map()获取的数据是Stream<Stream<T>>,此时如果想要继续过滤就有点麻烦,可以通过flatMap()
//例如调用下面自定义的fromStringToStream(String str)方法,返回多个Stream流,
Stream<Stream<Character>> streamStream = stringList.stream().map(ArrayTest::fromStringToStream);
//输出stringList中的所有char字符,由于调用ArrayTest类中中的fromStringToStream()方法
//返回的是Stream<Stream<Charcter>>,需要两层farEach()
streamStream.forEach(s -> {
s.forEach(System.out :: println);
});
//使用flamtMap,则会将多个Stream流重新组合为一个
Stream<Character> characterStream = stringList.stream().flatMap(ArrayTest::fromStringToStream);
characterStream.forEach(System.out :: println);
}
//将String字符串,转换为char集合,并将char集合转换为Stream流返回
public static Stream<Character> fromStringToStream(String str){
ArrayList<Character> list = new ArrayList<>();
for(Character c : str.toCharArray()){
list.add(c);
}
return list.stream();
}
3. 排序
1)方法概述
2)代码示例
@Test
public void test3(){
//排序
//1.sorted() 自然排序
List<Integer> integers = Arrays.asList(12, 34, 20, 70, 60);
integers.stream().sorted().forEach(System.out::println);
//如果想要自定义类对象实现自然排序,该类需要实现Comparator接口,制定排序规则否则报错
//否则使用sorted定制排序
//2.sorted(Comparator com) 定制排序(如果年龄相等则使用工资排序)
persionList.stream().sorted((p1, p2) ->{
int ageVal = Integer.compare(p1.getAge(),p2.getAge());
if(ageVal != 0){
return ageVal;
}else {
return Double.compare(p1.getSalary(), p2.getSalary());
}
}).forEach(System.out :: println);
}
四. Stream 的终止操作
终止操作,生成流的执行结果
1. 查找与匹配
1)方法概述
2) 代码示例
@Test
public void test4() {
List<Persion> persionList = new ArrayList<>();
persionList.add(new Persion("小明", 22, 2000.00));
//add()......
//一下的操作中都可以在加入中间操作实现过滤后再进行终止
//1.allMatch(Predicate p) 检查元素是否匹配,所有都是true,才是true
//判断是否集合中的所有年龄都大于18岁
Boolean b1 = persionList.stream().allMatch(p -> p.getAge() > 18);
//2.anyMatch(Predicate p) 检查是否有一个元素匹配,有一个为true则为true
//判断集合中是否有工资大于5000
Boolean b2 = persionList.stream().anyMatch(p -> p.getSalary() > 5000);
//3.noneMatch(Predicate p) 检查是否没有匹配的
//判断集合中是否有叫小明的,如果有则返回false
boolean b3 = persionList.stream().noneMatch(p -> p.getName().contains("小明"));
//4.findFirst 返回第一个元素,Option<>
Optional<Persion> persionOptional = persionList.stream().findFirst();
//5.findAny 返回当前流中任意元素
Optional<Persion> anyPersion = persionList.stream().findFirst();
//6.count 返回当前流中元素个数
//获取工资超过2000的个数
long count = persionList.stream().filter(p -> p.getSalary()>2000.00).count();
//7.max(Comparator c) 返回当前流中最大的元素
//返回最大工资的
Optional<Persion> max = persionList.stream().max((p1, p2) -> Double.compare(p1.getSalary(), p2.getSalary()));
//min(Comparator c) 返回最小的元素
//返回年龄最小的
Optional<Persion> min = persionList.stream().min((p1, p2) -> Integer.compare(p1.getAge(), p2.getAge()));
//返回最小年龄
persionList.stream().map(p -> p.getAge()).min(Integer :: compare);
//8.forEach(Consumer c) 内部迭代
persionList.stream().forEach(System.out :: println);
}
2. 规约
1)方法概述
2)代码示例
@Test
public void test5(){
//1.reduce(T identity, BinaryOperator) 将六种的元素结合起来得到一个值并返回
//查看BinaryOperator源码进行分析
//BinaryOperator继承BiFunction<T,T,T>接口,该接口传递两个T类型参数,返回一个T类型参数
//刚好符合Integer与Dubbo中的sum方法
//计算1-10的自然数的和
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer reduce = list.stream().reduce(0, Integer::sum);
//普通方式
Integer reduce2 = list.stream().reduce(0, (i1, i2) -> i1 + i2);
//2.reduce(BinaryOperator)
//获取集合中工资总和
List<Persion> persionList = new ArrayList<>();
persionList.add(new Persion("小明", 22, 2000.00));
//add()...
Optional<Double> reduce1 = persionList.stream().map(Persion::getSalary).reduce(Double::sum);
//普通方式
persionList.stream().map(Persion::getSalary).reduce((d1, d2) -> d1+d2);
}
3. 收集
1)方法概述
StreamAPI 收集 Collectors,将过滤终止的Stream结果数据收集为其他类型,与Stream收集终止操作配合使用
2)代码示例
@Test
public void test6(){
//1.collection(Collector c); 配合Collector中的静态方法,将Stream过滤终止后的数据
//收集为其他类型,例如List, set等
List<Persion> persionList = new ArrayList<>();
persionList.add(new Persion("小明", 22, 2000.00));
//add()......
//查找工资大于2000的员工返回List,或set
List<Persion> pList = persionList.stream().filter(p -> p.getSalary()>2000).collect(Collectors.toList());
pList.forEach(System.out :: println);
//返回set集合
Set<Persion> collect = persionList.stream().filter(p -> p.getSalary() > 2000).collect(Collectors.toSet());
//返回Collection,根据toCollection中的类型来决定返回值的类型
ArrayList<Persion> collect1 = persionList.stream().filter(p -> p.getSalary() > 2000)
.collect(Collectors.toCollection(ArrayList::new));
}
上一篇: Qt学习笔记6
下一篇: 用Python写一个中英动态翻译软件
推荐阅读
-
API接口调用并处理返回的json数据
-
MYSQL C API 学习汇总
-
乐字节-Java8新特性之Base64和重复注解与类型注解
-
关于php某些API的一些疑问,请大神指教
-
使用新浪微博API的OAuth认证发布微博实例_PHP教程
-
微信如何实现向浏览器注入JS API,并且调用方式就像浏览器原生API一样?
-
详解Spring Boot 中使用 Java API 调用 lucene
-
java8中使用java.util.Base64报“java.lang.IllegalArgumentException: Illegal base64 character d”
-
Node.js API详解之 util模块用法实例分析
-
vue3 + elementplus后台管理系统 + vue3核心Api实现 + Vuex4从零实现