第十四章lambda表达式与流处理

14.1 Iambda表达式

Iambda表达式简介

  1. lambda表达式可以用非常少的代码实现抽象方法。
  2. lambda表达式不能独立执行,因此必须实现函数式接口,并且会返回一个函数式接口的对象。
  3. lambdab表达式的语法非常特殊

语法格式:

()-> 结果表达式 

参数-> 结果表达式

(参数1,参数2...,参数n)-> 结果表达式

  • 第1行实现无参方法,单独写一对圆括号表示方法无参数,操作符右侧的结果表达式表示方法的返回值。
  • 第2行实现只有一个参数的方法,参数可以写在圆括号里,或者不写圆括号。
  • 第3行实现多参数的方法,所有参数按顺序写在圆括号里,且圆括号不可以省略。

lambda表达式也可以实现复杂方法,将操作符右侧的结果表达式换成代码块即可

语法格式如下:
()->{代码块
参数->(代码块}
(参数1,参数2,..参数n)->{代码块)

  • 第1行实现无参方法,方法体是操作符右侧代码块。
  • 第2行实现只有一个参数的方法,方法体是操作符右侧代码块。
  • 第3行实现多参数的方法,方法体是操作符右侧代码块。

lambda表达式的功能归纳总结,语法理解为:

()                       ->               {代码块}

这个方法            按照              这样的代码来实现

Iambda表达式实现函数式接口

1.函数式接口

开发者可以常见自定义的函数式接口

例如:

interface MyInterface{

        void method();

}

如果接口中包含一个以上的抽象方法,则不符合函数式接口的规范,这样的接口不能用Iambda表达式创建匿名对象

2.Iambda表达式实现无参数抽象方法

例题14.1

 
  1. interface SayHiInterface{ //例题14.1

  2. String say();//抽象方法接口

  3. }

  4. public class NoParamterDemo {

  5. public static void main(String[] args) {//利用匿名内部类补全方法体

  6. //lambda表达式实现发招呼接口,返回抽象方法结果

  7. SayHiInterface pi=()->"你好啊,这是lanbda表达式";

  8. System.out.print(pi.say());

  9. }

  10. }

运行结果如下:

3.lambda表达式实现有参抽象方法

如果抽象方法中只有一个参数,lambda表达式则可以省略圆括号

例题14.2

 
  1. interface AddInt{

  2. int add(int a,int b);

  3. }

  4. public class ParamDemo {

  5. public static void main(String[] args) {

  6. // TODO Auto-generated method stub

  7. /*无参数 AddInt ai1 = new AddInt() {

  8. public int add(int a,int b) {

  9. return a+b;

  10. }

  11. };

  12. System.out.println("匿名内部类:" + ai1.add(3,5));

  13. //使用Lambda表示式补全方法体

  14. AddInt ai2 = (a, b) ->{

  15. return a+b;

  16. };

  17. System.out.println("lambda表达式:" + ai2.add(3,5));

  18. }

  19. }*/

  20. AddInt np=(x,y)->x+y; //表达式

  21. int result=np.add(15,26); //调用接口方法

  22. System.out.println("相加结果:"+result); //输出相加结果

  23. }

  24. }

 运行结果如下:

lambda表达式中的参数不需要与抽象方法的参数名称相同,但顺序必须相同

4.lambda表达式使用代码块

lambda表达式会自动判断返回值类型是否符合抽象方法的定义

例题14.3

 
  1. interface CheckGrade{ //例题14.3

  2. String check(int grade); //查询成绩结果

  3. }

  4. public class GradeDemo {

  5. public static void main(String[] args) {

  6. // TODO Auto-generated method stub

  7. CheckGrade g =(n)-> { //lambda表达式实现代码块

  8. if (n>=90&& n<=100) { //如果成绩在90~100

  9. return"成绩为优"; //输出成绩为优

  10. }else if (n>=80&& n<=90) { //如果成绩在80~90

  11. return"成绩为良"; //输出成绩为良

  12. }else if (n>=60&& n<=80) { //如果成绩在60~80

  13. return"成绩为中"; //输出成绩为中

  14. }else if (n>=0&& n<=60) { //如果成绩在00~60

  15. return"成绩为差"; //输出成绩为差

  16. }else { //其他数字不是有效成绩

  17. return"成绩无效"; //输出成绩无效

  18. }

  19. };

  20. System.out.println(g.check(89));

  21. }

  22. }

运行结果如下:

 

Iambda表达式调用外部变量 

这些外部的变量有些可以被更改,有些则不能。例如,lambda表达式无法更改局部变量的值,但是却可以更改外部类的成员变量(也可以叫做类属性)的值他。

1.lambda表达式无法更改局部变量

局部变量在lambda表达式中默认被定义为final(静态)的,也就是说,lambda表达式只能调用局部变量,却不能改变其值。

例题14.4

 
  1. interface VariableInterface1{ //例题14.4

  2. void method();

  3. }

  4. public class VariableDemo1 {

  5. public static void main(String[] args) {

  6. // TODO Auto-generated method stub

  7. int value=100;

  8. VariableInterface1 v=()->{

  9. int num=value-90;

  10. value=12;

  11. };

  12. }

  13. }

运行结果如下:

2.lambda表达式可以更改类成员变量

类成员变量是在lambda表达式中不是被final修饰的,所以lambda表达式可以改变其值

例题14.5

 
  1. interface VariableInterface2{ //测试接口

  2. void method(); //测试方法

  3. }

  4. public class VariableDemo2 { //测试类

  5. int value = 100; //创建类成员变量

  6. public void action() { //创建类成员方法

  7. VariableInterface2 v=()->{ //实现测试接口

  8. value =-12; //更改成员变量,没提示任何错误

  9. };

  10. System.out.println("运行接口方法前value="+value); //运行接口方法前先输出成员变量值

  11. v.method(); //运行接口方法

  12. System.out.println("运行接口方法后value="+value); //运行接口方法后再输出成员变量值

  13. }

  14. public static void main(String[] args) {

  15. VariableDemo2 demo = new VariableDemo2(); //创建测试类对象

  16. demo.action(); //执行测试类方法

  17. }

  18. }

运行结果如下:

  • lambda 表达式可以调用并修改类成员变量的值
  • lambda表达式只是描述了抽象方法是如何实现的,在抽象方法没有被调用前,lambda表达式中的代码并没有被执行,所以运行抽象方法之前类成员变量的值不会发生变化。
  • 只要抽象方法被调用,就会执行lambda 表达式中的代码,类成员变量的值就会被修改。

Iambda表达式与异常处理

lambda 表达式中并有抛出异常的语法,这是因为lambda表达式会默认抛出抽象方法原有的异常,当此方法被调用时则要进行异常处理。

例题14.6

 
  1. import java.util.Scanner;

  2. interface AntiaddictInterface{ //防沉迷接口

  3. boolean check(int age)throws UnderAgeException; //抽象检查方法,抛出用户未成年异常

  4. }

  5. class UnderAgeException extends Exception{ //自定义未成年异常

  6. public UnderAgeException(String message) { //有参构造方法

  7. super(message); //调用原有父类构造方法

  8. }

  9. }

  10. public class ThrowExceptionDemo { //测试类

  11. public static void main(String[] args) { //主方法

  12. //lambda表达式创建AntiaddictInterface对象,默认抛出原有异常

  13. AntiaddictInterface ai =(a)->{

  14. if(a<18) { //如果年龄小于18岁

  15. throw new UnderAgeException("未满18周岁,开启防沉迷模式!"); //抛出异常

  16. }else { //否则

  17. return true; //验证通过

  18. }

  19. };

  20. Scanner sc = new Scanner(System.in); //创建控制台扫描器

  21. System.out.print("请输入年龄:"); //控制台提示

  22. int age = sc.nextInt(); //获取用户输入的年龄

  23. try { //因为接口方法抛出异常,所以此处必须捕捉异常

  24. if(ai.check(age)) { //验证年龄

  25. System.out.println("欢迎进入XX世界");

  26. }

  27. }catch(UnderAgeException e) { //控制台打印异常警告

  28. System.out.println(e);

  29. }

  30. sc.close(); //关闭扫描器

  31. }

  32. }

运行结果如下:

14.2方法的引用

引用静态方法

语法:

类名::静态方法名 

新的操作符“::”,中间无空格,左边表示方法所属的类名,右边是方法名,语法中方法名是没有括号的。 

例题14.7

 
  1. interface StaticMethodInterface{ //测试接口 例题14.7

  2. int method(int a, int b); //抽象方法

  3. }

  4. public class StaticMethodDemo {

  5. static int add(int x,int y) { //静态方法,返回两个参数相加的结果

  6. return x +y; //返回相加结果

  7. }

  8. public static void main(String[] args) {

  9. // TODO Auto-generated method stub

  10. StaticMethodInterface sm= StaticMethodDemo::add; //引用StaticMethodDemo类的静态方法

  11. int result = sm.method(15,16); //直接调用接口方法获取结果

  12. System.out.println("接口方法结果:"+result); //输出结果

  13. }

  14. }

运行结果如下:

 

 引用成员方法

引用成员方法的语法:

对象名::成员方法名

操作符左侧必须是一个对象名,而不是类名。 

例题14.8

 
  1. import java.text.SimpleDateFormat; //例题14.8

  2. import java.util.Date;

  3. interface InstanceMethodInterface{ //测试创建接口

  4. String method(Date date); //带参数的抽象方法

  5. }

  6. public class InstanceMethodDemo {

  7. public String format(Date date) { //格式化方法

  8. //创建日期格式化对象,并指定日期格式

  9. SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd");

  10. return sdf.format(date); //返回格式化结果

  11. }

  12. public static void main(String[] args) {

  13. // TODO Auto-generated method stub

  14. InstanceMethodDemo demo = new InstanceMethodDemo(); //创建类对象

  15. InstanceMethodInterface im = demo::format; //引用类对象的方法

  16. Date date = new Date(); //创建日期对象

  17. System.out.println("默认格式:"+date); //输出日期对象默认格式

  18. System.out.println("接口输出的格式:"+im.method(date)); //输出经过接口方法处理过的格式

  19. }

  20. }

运行结果如下:

引用带泛型的方法 (14.9/12/13不用写博客)

引用构造方法

Iambda表达式有3种引用构造方法的语法,分别是引用无参数构造方法、引用有参构造方法和引用数构造方法

1.引用无参构造方法

语法:

类名::new

注意:new关键字之后没有圆括号,也没有参数的定义 

例题14.10

 
  1. interface ConstructorsInterface1{ //构造方法接口

  2. ConstructorsDemo1 action(); //调用无参方法

  3. }

  4. public class ConstructorsDemo1 { //测试类

  5. public ConstructorsDemo1() { //无参构造方法

  6. System.out.print("无参构造方法");

  7. }

  8. public ConstructorsDemo1(int a) { //有参构造方法

  9. System.out.print("有参构造方法"+ a);

  10. }

  11. public static void main(String[] args) {

  12. ConstructorsInterface1 ci = ConstructorsDemo1::new; //引用ConstructorsDemo1类的构造方法

  13. ci.action(); //通过无参方法创建对象

  14. }

  15. }

运行结果如下:

2.引用有参构造方法

引用有参构造方法的语法与引用无参构造方法一样。区别就是函数式接口的抽象方法是有参数的

例题14.11

 
  1. interface ConstructorsInterface2{ //构造方法接口

  2. ConstructorsDemo2 action(int i); //调用有参方法

  3. }

  4. public class ConstructorsDemo2 { //测试类

  5. public ConstructorsDemo2(){ //无参构造方法

  6. System.out.print("调用无参构造方法");

  7. }

  8. public ConstructorsDemo2(int i) { //有参构造方法

  9. System.out.println("有参构造方法,参数为:"+i);

  10. }

  11. public static void main(String[] args) {

  12. ConstructorsInterface2 a = ConstructorsDemo2::new; //引用ConstructorsDemo1类的构造方法

  13. ConstructorsDemo2 b = a.action(123); //通过无参方法创建对象

  14. }

  15. }

运行结果如下:

3.引用数组构造方法

 语法;

类名[]::new

14.2.5Fuction接口 

这个接口有以下两个泛型:

  1. T:被操作的类型,可以理解为方法参数类型。
  2. R:操作结果类型,可以理解为方法的返回类型。

Function 接口是函数式接口,所以只有一个抽象方法,但是Function 接口还提供
方法以方便开发者对函数逻辑进行更深层的处理。

Function 接口方法如表14.1所示

14.3流处理

流处理有点类似数据库的 SQL 语句,可以执行非常复杂的过滤、映射、查找和收集功能,并且代码量很少。唯一的缺点是代码可读性不高。

对员工数据进行流处理

员工集合的详细数据如下

例题14.14

 
  1. import java.util.ArrayList;

  2. import java.util.List;

  3. public class Employee {

  4. private String name; //姓名

  5. private int age; //年龄

  6. private double salary; //工资

  7. private String sex; //性别

  8. private String dept; //部门

  9. public Employee(String name, int age, double salary, String sex, String dept) {

  10. super();

  11. this.name = name;

  12. this.age = age;

  13. this.salary = salary;

  14. this.sex = sex;

  15. this.dept = dept;

  16. }

  17. @Override

  18. public String toString() {

  19. return "Employee [name=" + name + ", age=" + age + ", salary=" + salary + ", sex=" + sex + ", dept=" + dept

  20. + "]";

  21. }

  22. public String getName() {

  23. return name;

  24. }

  25. public int getAge() {

  26. return age;

  27. }

  28. public double getSalary() {

  29. return salary;

  30. }

  31. public String getSex() {

  32. return sex;

  33. }

  34. public String getDept() {

  35. return dept;

  36. }

  37. static List<Employee> getEmpList(){

  38. List<Employee> list=new ArrayList<Employee>();

  39. list.add(new Employee("老张",40,9000,"男","运营部"));

  40. list.add(new Employee("小刘",24,5000,"女","开发部"));

  41. list.add(new Employee("大刚",32,7500,"男","销售部"));

  42. list.add(new Employee("翠花",28,5500,"女","销售部"));

  43. list.add(new Employee("小马",21,3000,"男","开发部"));

  44. list.add(new Employee("老王",35,6000,"女","人事部"));

  45. list.add(new Employee("小王",21,3000,"女","人事部"));

  46. return list;

  47. }

  48. }

 方法如下:

Source——Generate ConStructor using Fields

Source——Generate toStrinig() 

Source——Generate Getterd and Setters

点击右边的Select Getters 

14.3.1 Stream接口简介

流处理的接口都定义在java.uil.stream 包下。BaseStream接口是最基础的接口,但最常用的是BaseStream 接口的一个子接口——Stream 接口,基本上绝大多数的流处理都是在Stream 接口上实现的。Stream 接口是泛型接口,所以流中操作的元素可以是任何类的对象。

Stream 接口的常用方法如表14.3所示。

Collection 接口新增两个可以获取流对象的方法。第一个方法最常用,可以获取集合的顺序流,方法如下:

Stream<E> stream();

第二个方法可以获取集合的并行流,方法如下:

Stream<E> parallelstream();

因为所有集合类都是Collection 接口的子类,如ArrayList类、HashSet类等,所以这些类都可以进行流处理。例如:

List<integer> list = new ArrayList<Integer>();  //创建集合

Streamcinteger> s = list.stream();//获取集合流对象

14.3.2 Optional类

 Optional 类是用final 修饰的,所以不能有子类。Optional类是带有泛型的类,所以该类可以保存
任何对象的值。
从Optional类的声明代码中就可以看出这些特性,JDK中的部分代码如下:

 
  1. public final class Optional<T>{

  2. private final T value;

  3. } //省略其他代码

Optional 类中有一个叫作value的成员属性,这个属性就是用来保存具体值的。value 是用泛型了
修饰的,并且还用了final 修饰,这表示一个 Optional 对象只能保存一个值。
Optional类提供了很多封装、校验和获取值的方法,这些方法如下:

例题14.15

 
  1. import java.util.Optional;

  2. public class OptionalDemo {

  3. public static void main(String[] args) {

  4. Optional<String>strValue = Optional.of("hello"); //创建有值对象

  5. boolean haveValueFlag = strValue.isPresent(); //判断对象中的值是不是空的

  6. System.out.println("strValue对象是否有值:"+haveValueFlag);

  7. if(haveValueFlag) { //如果不是空的

  8. String str = strValue.get(); //获取对象中的值

  9. System.out.println("strValue对象的值是:"+str);

  10. }

  11. Optional<String> noValue = Optional.empty(); //创建空值对象

  12. boolean noValueFlag = noValue.isPresent(); //判断对象中的值是不是空的

  13. System.out.println("noValue对象是否有值:"+noValueFlag);

  14. if(noValueFlag) { //如果不是空的

  15. String str = noValue.get(); //获取对象中的值

  16. System.out.println("noValue对象的值是:"+str);

  17. }else { //如果是空的

  18. String str = noValue.orElse("使用默认值"); //使用默认值

  19. System.out.println("noValue对象是:"+str);

  20. }

  21. }

  22. }

运行结果如下:

14.3.3 Collectors类 

此类提供了很多实用的数据加工方法,如下:

14.3.4 数据过滤 

数据过滤就是在杂乱的数据中筛选出需要的数据,类似 SQL 语句中的WHERE 关键字,给出一定
的条件,将符合条件的数据过滤并展示出来。

1. filter()方法

filterO方法是Stream 接口提供的过滤方法。该方法可以将lambda表达式作为参数,然后按照lambda表达式的逻辑过滤流中的元素。过滤出想要的流元素后,还需使用Stream 提供的collectO方法按照指定方法重新封装。

例题14.16

 
  1. import java.util.ArrayList;

  2. import java.util.List;

  3. import java.util.stream.Collectors;

  4. import java.util.stream.Stream;

  5. public class FilterOddDemo {

  6. static void printeach(String message,List list) { //输出集合元素

  7. System.out.print(message); //输出文字信息

  8. list.stream().forEach(n->{ //使用forEach方法遍历集合并打印元素

  9. System.out.print(n+"");

  10. });

  11. System.out.println(); //换行

  12. }

  13. public static void main(String[] args) {

  14. List<Integer> list = new ArrayList<>(); //创建空数组

  15. for(int i = 1; i<=10;i++) { //从1循环到10

  16. list.add(i); //给集合赋值

  17. }

  18. printeach("集合原有元素:",list); //输出集合元素

  19. Stream<Integer> stream = list.stream(); //获取集合流对象

  20. //将集合中的所有奇数过滤出来,把过滤结果重新赋值给流对象

  21. stream = stream.filter(n->n%2==1);

  22. //将流对象重新封装成一个List集合

  23. List<Integer> result = stream.collect(Collectors.toList());

  24. printeach("过滤之后的集合元素:",result); //输出集合元素

  25. }

  26. }

运行结果如下:

“获取流”“过滤流”“封装流”这三部分可以写在同一行代码中 

List<Integer> result = list.stream.().filter(n->%2==1).collect(Collectors.toList());

例题14.17

 
  1. import java.util.List;

  2. import java.util.stream.Collectors;

  3. import java.util.stream.Stream;

  4. public class FilerDemo{ //例题14.17

  5. public static void main(String[] args) {

  6. List<Employee> list=Employee.getEmpList();//获取公共类的测试数据

  7. Stream<Employee> stream = list.stream();//获取集合流对象

  8. //筛选年龄>30岁的员工

  9. stream=stream.filter(sx-> sx.getAge()>30);//将年龄大于30岁的员工过滤出来

  10. //限制条数

  11. stream = stream.limit(2);//将流对象重新封装成一个List集合

  12. List<Employee> result = stream.collect(Collectors.toList());//遍历结果集

  13. for (Employee sx : result) {//输出员工对象信息

  14. System.out.println(sx);

  15. }

  16. }

  17. }

运行结果如下:

2. distinct()方法 

该方法可以去除流中的重复元素,效果与SQL语句中的DISTINCT关键字一样

例题14.18

 
  1. import java.util.ArrayList;

  2. import java.util.List;

  3. import java.util.stream.Collectors;

  4. import java.util.stream.Stream;

  5. public class DistinctDemo { //例题14.18

  6. static void printeach(String message,List list) { //输出集合元素

  7. System.out.print(message); //输出文字信息

  8. list.stream().forEach(n->{ //使用fourEach方法遍历集合并打印元素

  9. System.out.println(n+"");

  10. });

  11. System.out.println(); //换行

  12. }

  13. public static void main(String[] args) {

  14. // TODO Auto-generated method stub

  15. List<Integer>list=new ArrayList<Integer>(); //创建集合

  16. list.add(1); //添加元素

  17. list.add(2);

  18. list.add(2);

  19. list.add(3);

  20. list.add(3);

  21. printeach("去重前:",list); //打印集合元素

  22. Stream<Integer>stream=list.stream(); //获取集合流对象

  23. stream=stream.distinct(); //取出流中的重复元素

  24. List<Integer>reslut=stream.collect(Collectors.toList());//将流对象重新封装成一个List集合

  25. printeach("去重后:",reslut);

  26. }

  27. }

运行结果如下:

3. Iimit()方法

Iimit()方法是Stream接口提供的方法,该方法可以获取流中前N个元素

例题14.19

 
  1. import java.util.List;

  2. import java.util.stream.Collectors;

  3. import java.util. stream.Stream;

  4. public class LimitDemo { //例题14.19

  5. public static void main(String[] args){

  6. List<Employee> list = Employee.getEmpList();//获取公共类的测试数据

  7. Stream<Employee> stream = list.stream();//获取集合流对象

  8. stream = stream.filter(people ->"女".equals(people.getSex()));//将所有女员工过滤出来

  9. stream = stream.limit(2);//取出前两位

  10. List<Employee> result = stream.collect(Collectors.toList());//将流对象重新封装成一个List集合

  11. for (Employee emp : result) {//遍历结果集

  12. System.out.println(emp);//输出员工对象信息

  13. }

  14. }

  15. }

运行结果:

4. skip方法 

skip()方法是Stream接口提供的方法,该方法可以忽略流中的前N个元素

例题14.20

 
  1. import java.util.List;

  2. import java.util.stream.Collectors;

  3. import java.util. stream.Stream;

  4. public class SkipDemo { //例题14.14

  5. public static void main(String[] args) {

  6. // TODO Auto-generated method stub

  7. List<Employee> list = Employee.getEmpList();//获取公共类的测试数据

  8. Stream<Employee> stream = list.stream();//获取集合流对象

  9. stream = stream.filter(people ->"男".equals(people.getSex()));//将所有男员工过滤出来

  10. stream = stream.skip(2);//取出前两位

  11. List<Employee> result = stream.collect(Collectors.toList());//将流对象重新封装成一个List集合

  12. for (Employee emp : result) {//遍历结果集

  13. System.out.println(emp);//输出员工对象信息

  14. }

  15. }

  16. }

运行结果:

14.3.5数据映射 

数据的映射和过滤概念不同:过滤是在流中找到符合条件的元素,映射是在流中获得具体的数据。Stream 接口提供了mapO方法用来实现数据映射,mapO方法会按照参数中的函数逻辑获取新的流对象,新的流对象中元素类型可能与旧流对象元素类型不相同。

例题14.21

 
  1. import java.util.List;

  2. import java.util.stream.Collectors;

  3. import java.util.stream.Stream;

  4. public class MapDemo {

  5. public static void main(String[] args) {

  6. List<Employee> list = Employee.getEmpList(); // 获取公共类的测试数据

  7. Stream<Employee> stream = list.stream(); // 获取集合流对象

  8. // 将所有开发部的员工过滤出来

  9. stream = stream.filter(people -> "开发部".equals(people.getDept()));

  10. // 将所有员工的名字映射成一个新的流对象

  11. Stream<String> names = stream.map(Employee::getName);

  12. // 将流对象重新封装成一个List集合

  13. List<String> result = names.collect(Collectors.toList());

  14. for (String emp : result) { // 遍历结果集

  15. System.out.println(emp); // 输出所有姓名

  16. }

  17. }

  18. }

运行结果如下:

例题14.22

 
  1. import java.util.List;

  2. import java.util.stream.DoubleStream;

  3. import java.util.stream.Stream;

  4. public class MapToInDemo {

  5. public static void main(String[] args) {

  6. List<Employee> list = Employee.getEmpList(); // 获取公共类的测试数据

  7. Stream<Employee> stream = list.stream(); // 获取集合流对象

  8. // 将所有开发部的员工过滤出来

  9. stream = stream.filter(people -> "销售部".equals(people.getDept()));

  10. // 将所有员工的名字映射成一个新的流对象

  11. DoubleStream salarys = stream.mapToDouble(Employee::getSalary);

  12. // 统计流中元素的数学总和

  13. double sum = salarys.sum();

  14. System.out.println("销售部一个月的薪资总额:"+sum);

  15. }

  16. }

运行结果如下:

14.3.6 数据查找
1.allMatch()方法

该方法会判断流中的元素是否全部符合某一条件,返回结果是boolean值

例题14.23

 
  1. import java.util.List;

  2. import java.util.stream.Stream;

  3. public class AllMatchDemo {

  4. public static void main(String[] args) {

  5. List<Employee> list = Employee.getEmpList(); // 获取公共类的测试数据

  6. Stream<Employee> stream = list.stream(); // 获取集合流对象

  7. // 判断所有员工的年龄是否都大于25

  8. boolean result = stream.allMatch(people -> people.getAge() > 25);

  9. System.out.println("所有员工是否都大于25岁:" + result); // 输出结果

  10. }

  11. }

运行结果如下:

2.anyMatch方法()方法

该方法会判断流中的元素是否有符合某一条件

例题14.24

 
  1. import java.util.List;

  2. import java.util.stream.Stream;

  3. public class AnyMatchDemo {

  4. public static void main(String[] args) {

  5. List<Employee> list = Employee.getEmpList(); // 获取公共类的测试数据

  6. Stream<Employee> stream = list.stream(); // 获取集合流对象

  7. // 判断员工是否有的年龄大于等于40

  8. boolean result = stream.anyMatch(people -> people.getAge() >= 40);

  9. System.out.println("员工中有年龄在40或以上的吗?:" + result); // 输出结果

  10. }

  11. }

运行结果如下:

3.noneMatch()方法

该方法会判断流中的所有元素是否都不符合某一条件

例题14.25

 
  1. import java.util.List;

  2. import java.util.stream.Stream;

  3. public class NoneMathchDemo {

  4. public static void main(String[] args) {

  5. List<Employee> list = Employee.getEmpList(); // 获取公共类的测试数据

  6. Stream<Employee> stream = list.stream(); // 获取集合流对象

  7. // 判断公司中是否不存在薪资小于2000的员工?

  8. boolean result = stream.noneMatch(people -> people.getSalary() <2000 );

  9. System.out.println("公司中是否不存在薪资小于2000元的员工?:" + result);// 输出结果

  10. }

  11. }

运行结果如下:

4.findFirst()方法

这个方法会返回符合条件的第一个元素

例题14.26

 
  1. import java.util.List;

  2. import java.util.Optional;

  3. import java.util.stream.Stream;

  4. public class FindFirstDemo {

  5. public static void main(String[] args) {

  6. // 获取公共类的测试数据

  7. List<Employee> list = Employee.getEmpList();

  8. Stream<Employee> stream = list.stream(); // 获取集合流对象

  9. // 过滤出21岁的员工

  10. stream = stream.filter(people -> people.getAge() == 21);

  11. Optional<Employee> young = stream.findFirst(); // 获取第一个元素

  12. Employee emp = young.get(); // 获取员工对象

  13. System.out.println(emp); // 输出结果

  14. }

  15. }

运行结果如下:

这个方法的返回值不是boolean值,而是一个Optional对象

14.3.7 数据收集
1.数据统计

不仅可以筛选出特殊元素,还可以对元素的属性进行统计计算

例题14.27

 
  1. import java.util.Comparator; // 比较器接口

  2. import java.util.List;

  3. import java.util.Optional;

  4. import java.util.stream.Collectors;

  5. public class ReducingDemo {

  6. public static void main(String[] args) {

  7. List<Employee> list = Employee.getEmpList(); // 获取测试数据

  8. long count = list.stream().count(); // 获取总人数

  9. // 下行代码也能实现获取总人数效果

  10. // count = stream.collect(Collectors.counting());

  11. System.out.println("公司总人数为:" + count);

  12. // 通过Comparator比较接口,比较员工年龄,再通过Collectors的maxBy()方法取出年龄最大的员工的Optional对象

  13. Optional<Employee> ageMax = list.stream().collect(Collectors.maxBy(Comparator.comparing(Employee::getAge)));

  14. Employee older = ageMax.get();// 获取员工对象

  15. System.out.println("公司年龄最大的员工是:\n " + older);

  16. // 通过Comparator比较接口,比较员工年龄,再通过Collectors的minBy()方法取出年龄最小的员工的Optional对象

  17. Optional<Employee> ageMin = list.stream().collect(Collectors.minBy(Comparator.comparing(Employee::getAge)));

  18. Employee younger = ageMin.get();// 获取员工对象

  19. System.out.println("公司年龄最小的员工是:\n " + younger);

  20. // 统计公司员工薪资总和

  21. double salarySum = list.stream().collect(Collectors.summingDouble(Employee::getSalary));

  22. System.out.println("公司的薪资总和为:" + salarySum); // 输出结果

  23. // 统计公司薪资平均数

  24. double salaryAvg = list.stream().collect(Collectors.averagingDouble(Employee::getSalary));

  25. // 使用格式化输出,保留2位小数

  26. System.out.printf("公司的平均薪资为:%.2f\n", salaryAvg);

  27. // 创建统计对象,利用summarizingDouble()方法获取员工薪资各方面的统计数据

  28. java.util.DoubleSummaryStatistics s = list.stream().collect(Collectors.summarizingDouble(Employee::getSalary));

  29. System.out.print("统计:拿薪资的人数=" + s.getCount() + ", ");

  30. System.out.print("薪资总数=" + s.getSum() + ", ");

  31. System.out.print("平均薪资=" + s.getAverage() + ", ");

  32. System.out.print("最大薪资=" + s.getMax() + ", ");

  33. System.out.print("最小薪资=" + s.getMin() + "\n");

  34. // 将公司员工姓名拼成一个字符串,用逗号分隔

  35. String nameList = list.stream().map(Employee::getName).collect(Collectors.joining(", "));

  36. System.out.println("公司员工名单如下:\n " + nameList);

  37. }

  38. }

运行结果如下:

2.数据分组

将流中元素按照指定的条件分开保存

数据分组有一级分组和多级分组

一级分组:将所有数据按照一个条件进行分类

例题14.28

 
  1. import java.util.List;

  2. import java.util.Map;

  3. import java.util.Set;

  4. import java.util.stream.Collectors;

  5. import java.util.stream.Stream;

  6. public class GroupDemo1{

  7. public static void main(String[] args) {

  8. // TODO Auto-generated method stub

  9. List<Employee> list = Employee.getEmpList();

  10. Stream<Employee>stream=list.stream();

  11. Map<String,List <Employee>> map = stream.collect(Collectors.groupingBy(Employee::getDept));

  12. Set<String>depts=map.keySet();

  13. for(String dept:depts) {

  14. System.out.println(dept+"员工信息如下:");

  15. List<Employee>temp=map.get(dept);

  16. for(Employee e:temp) {

  17. System.out.println(e);

  18. }

  19. System.out.println();

  20. }

  21. }

  22. }

运行结果如下:

难点:

  1. 分组规则是一个函数,这个函数是由Collectors收集器类调用的,而不是Stream流对象。
  2. Map<K,List<T>>有两个泛型,第一个泛型是组的类型,第二个是组内的元素集合类型。实例中按照部门名称分组,所以K的类型是String 类型;部门内的元素是员工集合,所以List集合泛型T的类型就应该是Employee类型

例题14.29

 
  1. import java.util.List;

  2. import java.util.Map;

  3. import java.util.Set;

  4. import java.util.function.Function;

  5. import java.util.stream.Collectors;

  6. import java.util.stream.Stream;

  7. public class GroupingDemo2 {

  8. public static void main(String[] args) {

  9. List<Employee> list = Employee.getEmpList(); // 获取公共类的测试数据

  10. Stream<Employee> stream = list.stream(); // 获取集合流对象

  11. // 一级分组规则方法,按照员工部门进行分级

  12. Function<Employee, String> deptFunc = Employee::getDept;

  13. // 二级分组规则方法,按照员工部门进行分级

  14. Function<Employee, String> sexFunc = Employee::getSex;

  15. // 将流中的数据进行二级分组,先对员工部分进行分组,在对员工性别进行分组

  16. Map<String, Map<String, List<Employee>>> map = stream

  17. .collect(Collectors.groupingBy(deptFunc, Collectors.groupingBy(sexFunc)));

  18. // 获取Map的中的一级分组键集合,也就是部门名称集合

  19. Set<String> deptSet = map.keySet();

  20. for (String deptName : deptSet) { // 遍历部门名称集合

  21. // 输出部门名称

  22. System.out.println("【" + deptName + "】 部门的员工列表如下:");

  23. // 获取部门对应的二级分组的Map对象

  24. Map<String, List<Employee>> sexMap = map.get(deptName);

  25. // 获得二级分组的键集合,也就是性别集合

  26. Set<String> sexSet = sexMap.keySet();

  27. for (String sexName : sexSet) { // 遍历部门性别集合

  28. // 获取性别对应的员工集合

  29. List<Employee> emplist = sexMap.get(sexName);

  30. System.out.println(" 【" + sexName + "】 员工:"); // 输出性别种类

  31. for (Employee emp : emplist) {// 遍历员工集合

  32. System.out.println(" " + emp); // 输出对应员工信息

  33. }

  34. }

  35. }

  36. }

  37. }

运行结果如下:

难点:

  1. 实例中两个 groupingBy0方法的参数不一样,一个是 groupingBy(性别分组规则),另一个是groupingBy(部门分组规则,groupingBy(性别分组规则))。
  2. 获得的Map 对象中,还嵌套了Map对象,它的结构是这样的:Map<部门,Map<性别,List<员工>>>

从左数,第一个Map对象做了一级分组,第二个Map对象做了二级分组。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值