什么是Stream

Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行测操作,可以执行非常复杂的查找,过滤和映射数据的操作,使用Stream API对集合数据进行操作就类似于使用SQL执行的数据库查询查询,Stream API提供了一种高效且易于使用的处理数据的方式。
流(Stream)是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列,“集合讲的是数据,流讲的是计算”,需要注意的是以下三点
1. Stream自己不会存储元素
2. Stream不会改变源对象,相会,他们会返回一个持有结果的新的Stream
3. Stream操作是延迟执行的,这意味着他们会等到需要结果的时候才执行。

Stream使用方法

  1. 创建Stream:一个数据源(集合、数组)获取一个流
  2. 中间操作:一个中间操作链,对数据源的数据进行处理
  3. 终止操作:一个终止操作,执行中间操作链,并产生结果。

创建Stream的方法

  1. 通过Collection系列提供的stream()或parallelStream(),如下:
  2. 通过Arrays中的静态方法stream()方法获取流
  3. 通过Stream类中的静态方法of()
  4. 创建无限流

示例如下:

@Test
public void test1(){// 1.通过Collection系列提供的stream()或parallelStream()List<String> list = new ArrayList<>();Stream<String> stream = list.stream();// 2.通过Arrays中的静态方法stream()方法获取流Employee[] emps = new Employee[10];Stream<Employee> stream1 = Arrays.stream(emps);// 3.通过Stream类中的静态方法of()Stream<String> stream2 = Stream.of("AA","BB","CC");// 4.创建无限流//迭代Stream<Integer> stream3 = Stream.iterate(0,(x) -> x+2);//只要前10个(中间操作)stream3.limit(10).forEach(System.out::println);//打印了所有的中间流操作//stream3.forEach(System.out::println);//4.2生成Stream.generate(() -> Math.random()).limit(10).forEach(System.out::println);
}

中间操作

  • filter—-接受lambda,从流中排除某一些元素
  • limit—-截断流,使其元素不超过给定的数量
  • skip(n)—-跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流
  • distinct—-筛流,通过流生成元素的hashcode()和equals()去除重复元素
filter示例
@Test
public void test1(){//中间操作Stream<Employee> stream = employees.stream().filter((e) -> {System.out.println("中间操作");return  e.getAge() > 16;});//终止操作stream.forEach(System.out::println);
}
惰性求值和内部迭代
  1. 如果没有终止操作,是不会打印中间操作的,这就是流只有需要结果的时候才会被调用,这就是惰性求值。
  2. 上述打印是Stream自己给我们迭代输出的,这个就是内部迭代。
筛选和切片示例如下
@Test
public void test1(){//中间操作Stream<Employee> stream = employees.stream().filter((e) -> e.getAge() > 15).limit(4).skip(1).distinct();//终止操作stream.forEach(System.out::println);
}

说明:由于distinct是根据hashcode()和equals()去重,所以Employee中要重写equals和hashCode方法。

映射

  1. map(Function f) 接收一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素。
  2. mapToDouble(ToDoubleFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream
  3. mapToLong(ToLongFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream
  4. flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

map示例如下

@Test
public void test2(){List<String> list = Arrays.asList("aaa","bbb","ccc","ddd");list.stream().map((str) -> str.toUpperCase()).forEach(System.out::println);
System.out.println("================");employees.stream().map(Employee::getName).forEach(System.out::println);
}

flatMap示例

@Test
public void test3(){List<String> list = Arrays.asList("aaa","bbb","ccc","ddd");Stream<Character> sm = list.stream().flatMap(TestMiddle::filterCharacter);sm.forEach(System.out::println);
}public static  Stream<Character> filterCharacter(String str){List<Character> list = new ArrayList<>();for(Character ch: str.toCharArray()){list.add(ch);}return list.stream();
}

排序

sorted()-自然排序(comparable)
@Testpublic void test4(){List<String> list = Arrays.asList("ccc","aaa","bbb","eee");list.stream().sorted().forEach(System.out::println);}
}
sorted(Comparator com)-定制排序(Comparator)
@Test
public void test5(){employees.stream().sorted((e1,e2) -> {if(e1.getAge().equals(e2.getAge())){return e1.getName().compareTo(e2.getName());}else{return e2.getAge().compareTo(e2.getAge());}}).forEach(System.out::println);
}

终止操作

终止操作会从流的流水线生成结果,该结果可以是任何不是流的值,例如:List、Integer、void。

查找和匹配
  1. allMatch(Predicate p) 检查是否匹配所有的元素
  2. anyMatch(Predicate p) 检查是否至少匹配一个元素
  3. noneMatch(Predicate p) 检查是否没有匹配所有的元素
  4. findFirst() 返回第一个元素
  5. findAny() 返回当前流中的任意元素
  6. count() 返回流中元素个数
  7. max(Comparator c) 返回流中最大值
  8. min(Comparator c) 返回流中最小值
  9. forEach(Consumer c) 内部迭代

示例如下:

public class TestStreamAPI {List<Employee> employees = Arrays.asList(new Employee("张三",16,9999.99, Employee.Status.FREE),new Employee("李四",18,8888.99, Employee.Status.VOCATION),new Employee("王五",20,7777.99, Employee.Status.BUSY),new Employee("赵六",22,6666.99, Employee.Status.FREE),new Employee("田七",24,5555.99, Employee.Status.BUSY),new Employee("小八",26,4444.99, Employee.Status.VOCATION),new Employee("陈九",28,3333.99, Employee.Status.VOCATION),new Employee("王五",32,9999.99, Employee.Status.BUSY),new Employee("王五",34,9999.99, Employee.Status.FREE),new Employee("王五",36,9999.99, Employee.Status.BUSY));@Testpublic void test1(){//检查是否所有的状态为BUSY状态Boolean b1 =  employees.stream().allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));//检查是否至少匹配一个元素Boolean b2 = employees.stream().anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));//检查是否没有匹配元素Boolean b3 = employees.stream().noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));//先按照工资排序,再去除第一个元素放在Option容器中Optional<Employee> op = employees.stream().sorted((e1,e2) -> Double.compare(e1.getSalay(),e2.getSalay())).findFirst();System.out.println(op.get());//findAny返回当前流中的任意元素,先过滤再返回一个,//mployees.stream()实现的是串行流,每次返回的值一定的。//employees.parallelStream()实现的是并行流 ,返回的就是满足条件的随机结果。Optional<Employee> op2 = employees.parallelStream().filter((e) -> e.getStatus().equals(Employee.Status.BUSY)).findAny();System.out.println(op2.get());//返回流中元素个数Long count = employees.stream().count();//返回流中最大值Optional<Employee> op1 = employees.stream().max((e1,e2) -> Double.compare(e1.getSalay(),e2.getSalay()));System.out.println(op1.get());//返回流中最低工资Optional<Double> op3 = employees.stream().map(Employee::getSalay).min(Double::compare);System.out.println(op3.get());}
}
归约

reduce(T iden,BinaryOperator b)可以将流中元素反复结合起来,得到一个值,返回T,示例如下:

@Test
public void test2(){List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);Integer sum = list.stream().reduce(0,(x,y) -> x+y);System.out.println(sum);//计算工资的总和Optional<Double> op = employees.stream().map(Employee::getSalay).reduce(Double::sum);System.out.println(op.get());
}

上述代码中使用map得到所有的工资,再有reduce将所有的工资累加,map和reduce配合使用情况比较多。

收集

collect(Collector c)将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。
Colletor接口中的方法实现决定了如何对流执行收集操作(如收集到List,Set,Map),但是Collectors实用类提供了很多静态的方法,可以方便的创建常用收集器实例,具体方法与实例如下:
1. toList 返回List 将流中元素搜集到List
2. toSet 返回Set 将流中元素手机到Set
3. toCollection 返回Collection 把流中元素收集到创建的集合中
4. counting 返回Long 计算流中元素的个数
5. summinglnt 返回Integer 对流中元素的整数属性求和
6. averaginglnt 返回Double 计算流中元素Integer属性的平均值
7. summarizinglnt 返回IntSummaryStatistics 计算流中Integer属性的统计值,如平均值。
8. joining 返回String 连接流中每一个字符串
9. maxBy 返回Optional 根据比较器选择最大值
10. minBy 返回Optional 根据比较器选择最小值
11. reducing 归约产生的类型
12. collectionAndThen 转换函数返回的类型

实例如下:

@Test
public void test3(){//将名字添加到list中List<String> list = employees.stream().map(Employee::getName).collect(Collectors.toList());list.forEach(System.out::println);//将名字添加到Set中Set<String> set = employees.stream().map(Employee::getName).collect(Collectors.toSet());set.forEach(System.out::println);//将名字添加到特定的数据结构中HashSet<String> hashSet = employees.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));//总数Long count = employees.stream().collect(Collectors.counting());//平均数Double avg = employees.stream().collect(Collectors.averagingDouble(Employee::getSalay));//总和Double sum = employees.stream().collect(Collectors.summingDouble(Employee::getSalay));//最大值,返回工资最大的员工信息Optional<Employee> max = employees.stream().collect(Collectors.maxBy((e1,e2) -> Double.compare(e1.getSalay(),e2.getSalay())));//最小值,返回最小工资Optional<Double> min = employees.stream().map(Employee::getSalay).collect(Collectors.minBy(Double::compare));//按照状态分组Map<Employee.Status,List<Employee>> map = employees.stream().collect(Collectors.groupingBy(Employee::getStatus));map.get(Employee.Status.BUSY);//多级分组Map<Employee.Status,Map<String,List<Employee>>> map1 = employees.stream().collect(Collectors.groupingBy(Employee::getStatus,Collectors.groupingBy((e) ->{if(((Employee)e).getAge() <= 18){return "少年";}else if(((Employee)e).getAge() <= 26){return "中年";}else{return "老年";}})));System.out.println(map1);//分区。满足条件一个区,不满足条件的一个区Map<Boolean,List<Employee>> map2 = employees.stream().collect(Collectors.partitioningBy((e) -> e.getSalay() >5000));System.out.println(map2);//其他的一种获取方式DoubleSummaryStatistics dss = employees.stream().collect(Collectors.summarizingDouble(Employee::getSalay));System.out.println(dss.getSum());System.out.println(dss.getAverage());System.out.println(dss.getMax());//连接字符串String str = employees.stream().map(Employee::getName).collect(Collectors.joining(",","====","==="));
}

JavaEE进阶知识学习-----Java8新特性知识学习-4-1-StreamAPI相关推荐

  1. 快速学习Java8新特性第七讲——Optional类

    在<快速学习Java8新特性第五讲--强大的Stream API>这一讲中,我就已经提及到了Optional类.在这一讲中,我将对其做一个更加细致的讲解. Optional类是什么? Op ...

  2. java8新特性-stream学习

    java8除了提供了Lambda表达式,操作集合的Stream API也是新特性中最值得学习和掌握的,它大大简化了,我们操作数据集合的代码量的书写.简单来说Stream是一个抽象概念,可以通过查找,过 ...

  3. 【Java8新特性】关于Java8的Stream API,看这一篇就够了!!

    写在前面 Java8中有两大最为重要的改变.第一个是 Lambda 表达式:另外一个则是 Stream API(java.util.stream.*)  ,那什么是Stream API呢?Java8中 ...

  4. 【Java8新特性】浅谈方法引用和构造器引用

    写在前面 Java8中一个很牛逼的新特性就是方法引用和构造器引用,为什么说它很牛逼呢?往下看! 方法引用 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!这里需要注意的是:实现抽 ...

  5. 【Java8新特性】关于Java8中的日期时间API,你需要掌握这些!!

    写在前面 Java8之前的日期和时间API,存在一些问题,比如:线程安全的问题,跨年的问题等等.这些问题都在Hava8中的日期和时间API中得到了解决,而且Java8中的日期和时间API更加强大.立志 ...

  6. Java8新特性——Map的新方法

    今天是高考的日子,是大四师兄师姐答辩毕业的日子.一代又来,一代又去.好久没写博客,借此特殊日子整理一下前不久学java8新特性时写的代码,留下痕迹.(本博客的代码根据 java8新特性教程 学习整理, ...

  7. Java8新特性学习记录

    前言: Java 8 已经发布很久了,很多报道表明Java 8 是一次重大的版本升级.在Java Code Geeks上已经有很多介绍Java 8新特性的文章, 例如Playing with Java ...

  8. 【Java学习笔记之二十八】深入了解Java8新特性

    前言: Java 8 已经发布很久了,很多报道表明java 8 是一次重大的版本升级.在Java Code Geeks上已经有很多介绍Java 8新特性的文章,例如Playing with Java ...

  9. Java8新特性学习_001_(Lambda表达式,函数式接口,方法引用,Stream类,Optional类)

    目录 ■代码 ■代码运行结果 ■代码说明 ・44行:Stream的.foreach方法ー参数类型:函数式接口 ・82行:Interface中,default方法 ・92行   Stream的.max方 ...

  10. java8新特性-lambda表达式入门学习

    定义 jdk8发布新特性中,lambda是一大亮点之一.lambda表达式能够简化我们对数据的操作,减少代码量,大大提升我们的开发效率.Lambda 表达式"(lambda expressi ...

最新文章

  1. kaggle(一)训练猫狗数据集
  2. oracle配置的监听文件,配置oracle监听文件
  3. docker公共存储库_Docker Hub公共镜像仓库的使用
  4. Eclispe创建jsp文件,提示错误:“The import Xxx cannot be resolved“的解决方案
  5. pythonpyqt5线程暂停重启时间_PyQT5 停止死循环线程(监控文件是否修改)
  6. 【tool】firewall防火墙
  7. poj2176 Folding
  8. 年轻人必须在北上广工作吗
  9. 4个mos管驱动的全桥电路原理_逆变器工作原理
  10. 测试丢包_如何使用ping和tracert命令检测丢包
  11. 虚拟化查看服务器sn,查看服务器操作系统序列号
  12. 【省选模拟】20/04/18
  13. html添加桌面背景图片代码,背景图片加文字代码. 用HTML制作表格
  14. XYNU—ACM暑假集训第三次测试 贪心算法
  15. What Android Is
  16. 计算广告-商业化体系
  17. 计算机音乐天使重构,天使重构
  18. Spring Boot入门(24):Spring Boot事务 | 超级详细,建议收藏
  19. linux下hwclock及clock命令详解
  20. Tyvj4071放射性辐射尘题解

热门文章

  1. cisco2960(思科2960)
  2. 从培训机构出来的程序员,后来都怎么样了? | 程序员有话说
  3. 防止软件进行微信小程序自动刷票、免费投票刷票器手机版的安全设计
  4. 教育技术与c语言程序设计,2018年华东师范大学885教育技术与C程序设计考研复习资料...
  5. IDEA快捷方式改成eclipse的
  6. 京东登录滑条验证破解 -- 纯js方法
  7. Ubuntu 安装package提示依赖: XXX 但是它将不会被安装 解决方法
  8. 文献学习(part31)--Discovery of time-inconsecutive co-movement patterns of foreign currencies using ...
  9. MongoDB中balancer操作
  10. android语音识别sdk接入收费吗,百度语音识别开放平台SDK使用方法