zoukankan      html  css  js  c++  java
  • lambda

    一、lambda写法

    public class LambdaDemo1{
        
        // 定义接口
        interface Printer{
            void printer(String val);
        }
        
        // 定义一个打印方方法
        public void printSomething(String something,Printer printer){
            printer.printer(something);
        }
        
        public static void main(String[] args){
            LambdaDemo1 lambdaDemo1 = new LambdaDemo1();
            String something = "something";
            
            // 传统写法
            Printer printer = new Printer(){
                @Override
                public void printer(String val){
                    System.out.println("传统写法:"val);
                }
            };
            printSomething(something,printer);
            
            // lambda表达式 - 写法1
            // lambda表达式用 -> 连接参数和方法体
            // (String val) 参数 -- 左侧
            // {} 方法体 -- 右侧
            Printer printer = (String val) -> {
                 System.out.println("传统写法:"val);
            };
            printSomething(something,printer);
            
            // lambda表达式 - 写法2
            // 简写“写法1” -- 省略参数类型。
            // lambda可根据定义的接口和上下文自动识别参数的类型
            // 如果参数与类型不匹配会报错
            Printer printer = (val) -> {
                 System.out.println("传统写法:"val);
            };
            printSomething(something,printer);
            
            // lambda表达式 - 写法3
            // 简写“写法2”
            // 省略参数小括号:
            //		如果只有一个参数,可省略参数外层的()
            // 省略方法体花括号
            // 		如果方法体中只有一行代码,可省略方法体的{}
            Printer printer = val -> System.out.println("传统写法:"val);
            printSomething(something,printer);
          
            // lambda表达式 - 写法4
            // 简写“写法3”
            // printSomething中的参数printer
            // Printer printer = val -> System.out.println("传统写法:"val)
            printSomething(something,val -> System.out.println("传统写法:"val));
        }
    }
    

    二、Stream

    1、Stream源操作

    // 1、集合转Stream
    List<String> nameStrs = Arrays.asList("Monkey","Lion","Giraffe","Lemur");
    
    List<String> sorted  = nameStrs.stream() // 
        		.filter(s -> s.startsWith("L"))	// 过滤。判断条件:以字母"L"开头
        		.map(String::toUpperCase)		// 将过滤到的元素,全部变成大写
        		.sorted()	// 排序
        		.collect(toList());	// 组合成一个集合
    
    // 2、数组转Stream
    String[] players = {"kobe","james","curry","cyyt"};
    
    Stream.of(players)
          .filter(s -> s.startsWith("L"))
          .map(String::toUpperCase)
          .sorted()
          .collect(toList());	
    
    // 3、HashSet转Stream
    String[] players = {"kobe","james","curry","cyyt"};
    Set<String> set = new HashSet<>(players);
    
    List<String> sorted  = set.stream() // 
        		.filter(s -> s.startsWith("L"))	// 过滤。判断条件:以字母"L"开头
        		.map(String::toUpperCase)		// 将过滤到的元素,全部变成大写
        		.sorted()	// 排序
        		.collect(toList());	// 组合成一个集合
    
    // 4、行文本文件转Stream
    Files.lines(Paths.get("file.txt"))
         .filter(s -> s.startsWith("L"))	// 过滤。判断条件:以字母"L"开头
         .map(String::toUpperCase)		// 将过滤到的元素,全部变成大写
         .sorted()	// 排序
         .collect(toList());	// 组合成一个集合
    

    2、Stream中间操作

    2.1 无状态操作

    2.1.1、filter(过滤数据)
    public class Employee {
        private Integer id;
        private Integer age;
        private String gender;
        private String firstName;
        private String lastName;
        
        // 省略get set 构造
    }
    
    public class StreamFilterPredicate {
        
        public static void main(String[] args){
            Employee e1 = new Employee(1,20,"男","First1","Last1");
            Employee e2 = new Employee(2,21,"女","First2","Last2");
            Employee e3 = new Employee(3,24,"男","First3","Last3");
            Employee e4 = new Employee(4,22,"男","First4","Last4");
            Employee e5 = new Employee(5,21,"女","First5","Last5");
            Employee e6 = new Employee(6,25,"男","First6","Last6");
            Employee e7 = new Employee(7,23,"女","First7","Last7");
            Employee e8 = new Employee(8,25,"男","First8","Last8");
            Employee e9 = new Employee(9,26,"女","First9","Last9");
            Employee e10 = new Employee(10,21,"男","First10","Last10");
    
            List<Employee> employees = Arrays.asList(e1,e2,e3,e4,e5,e6,e7,e8,e9,e10);
    
            List<Employee> list = employees.stream()
                // Predicate 谓语
                // e.getAge() > 22 && e.getGender().equals("女") 谓词逻辑
                     .filter(e -> {e.getAge() > 22 && e.getGender().equals("女")})
                     .collect(Collectors.toList());
    
            System.out.println(list);
        }
        
    }
    

    谓词逻辑也可抽出来,复用

    public class Employee {
        private Integer id;
        private Integer age;
        private String gender;
        private String firstName;
        private String lastName;
        
        // 省略get set 构造
        
        public static Predicate<Employee> ageGreaterThan22 = x -> x.getAge() > 22;
        public static Predicate<Employee> genderWoman = x -> x.getGender().equals("女");
    }
    
    public class StreamFilterPredicate {
        
        public static void main(String[] args){
            Employee e1 = new Employee(1,20,"男","First1","Last1");
            Employee e2 = new Employee(2,21,"女","First2","Last2");
            Employee e3 = new Employee(3,24,"男","First3","Last3");
            Employee e4 = new Employee(4,22,"男","First4","Last4");
            Employee e5 = new Employee(5,21,"女","First5","Last5");
            Employee e6 = new Employee(6,25,"男","First6","Last6");
            Employee e7 = new Employee(7,23,"女","First7","Last7");
            Employee e8 = new Employee(8,25,"男","First8","Last8");
            Employee e9 = new Employee(9,26,"女","First9","Last9");
            Employee e10 = new Employee(10,21,"男","First10","Last10");
    
            List<Employee> employees = Arrays.asList(e1,e2,e3,e4,e5,e6,e7,e8,e9,e10);
    
            List<Employee> list = employees.stream()
                     // 支持
                     // .and():并且 
                     // .or():或者
                     // .negate():取反
                     .filter(Employee.ageGreaterThan22.and(Employee.genderWoman).negate())
                     .collect(Collectors.toList());
    
            System.out.println(list);
        }
        
    }
    
    2.1.2、map(转换数据)
    • 处理字符串类型集合元素
    public class StreamMap1 {
        public static void main(String[] args){
            List<String> alpha = Arrays.asList("Monkey", "Lion", "Giraffe", "Lemur");
    
            //不使用Stream管道流
            List<String> alphaUpper = new ArrayList<>();
            for (String s : alpha) {
                alphaUpper.add(s.toUpperCase());
            }
            System.out.println(alphaUpper); //[MONKEY, LION, GIRAFFE, LEMUR]
    
            // 使用Stream管道流
            List<String> collect = alpha.stream().map(String::toUpperCase).collect(Collectors.toList());
            // "方法引用":String::toUpperCase。效果和s -> s.toUpperCase()效果一样
            //List<String> collect = alpha.stream().map(s -> s.toUpperCase()).collect(Collectors.toList());
    
            System.out.println(collect); //[MONKEY, LION, GIRAFFE, LEMUR]
        }
    }
    
    • 处理非字符串类型集合元素
    // map()函数不仅可以处理数据,还可以转换数据的类型。如下:
    Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
        .mapToInt(String::length)
        .forEach(System.out::println);
    
    // 结果:
    // 6
    // 4
    // 7
    // 5
    
    除了mapToInt。还有maoToLong,mapToDouble等等用法。
    
    • 处理对象数据格式转换
    public class Employee {
        private Integer id;
        private Integer age;
        private String gender;
        private String firstName;
        private String lastName;
        
        // 省略get set 构造
    }
    
    public class StreamMap2 {
        public static void main(String[] args){
            
            Employee e1 = new Employee(1,23,"M","Rick","Beethovan");
            Employee e2 = new Employee(2,13,"F","Martina","Hengis");
            Employee e3 = new Employee(3,43,"M","Ricky","Martin");
            Employee e4 = new Employee(4,26,"M","Jon","Lowman");
            Employee e5 = new Employee(5,19,"F","Cristine","Maria");
            Employee e6 = new Employee(6,15,"M","David","Feezor");
            Employee e7 = new Employee(7,68,"F","Melissa","Roy");
            Employee e8 = new Employee(8,79,"M","Alex","Gussin");
            Employee e9 = new Employee(9,15,"F","Neetu","Singh");
            Employee e10 = new Employee(10,45,"M","Naveen","Jain");
    
            List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
            
            // 将每一个Employee的年龄增加一岁
            // 将性别中的“M”换成“male”,F换成Female。
            List<Employee> maped = employees.stream()
                .map(e -> {
                    e.setAge(e.getAge() + 1);
                    e.setGender(e.getGender().equals("M")?"male":"female");
                    return e;
                }).collect(Collectors.toList());
            
            
            List<Employee> peeked = employees.stream()
                .peek(e -> {
                    e.setAge(e.getAge() + 1);
                    e.setGender(e.getGender().equals("M")?"male":"female");
                }).collect(Collectors.toList());
            
            // .map()会return回一个新对象
            // .peek()是特殊的map函数。对同一个对象操作。实现效果一样。
            
            System.out.println(maped);
            System.out.println(peeked);
        }
    }
    
    2.1.3、flatMap(map展开)
    // map可以对管道流中的数据进行转换操作,但是如果管道中还有管道,数组中还有数组该如何处理?
    // 即:如何处理二维数组及二维集合类。
    // 实现一个简单的需求:
    // 		将“hello”,“world”两个字符串组成的集合,元素的每一个字母打印出来。
    //		如果不用Stream我们怎么写?写2层for循环,第一层遍历字符串,并且将字符串拆分成char数组,第二层for循环遍历char数组。
    public class StreamFlatMap {
        public static void main(String[] args){
            List<String> words = Arrays.asList("hello", "word");
            
            // .map():输出结果为:
            // 		java.util.stream.ReferencePipeline$Head@3551a94
    		// 		java.util.stream.ReferencePipeline$Head@531be3c5
            // 证明:
            // 		用map方法是做不到的,这个需求用map方法无法实现。
            //		map只能针对一维数组进行操作,数组里面还有数组,管道里面还有管道,它是处理不了每一个元素的。
    		words.stream()
            	.map(w -> Arrays.stream(w.split("")))
            	.forEach(System.out::println);
            
            // .flatMap():输出结果为:
            // h
    		// e
    		// l
    		// l
    		// o
    		// w
    		// o
    		// r
    		// d
            
            // flatMap可以理解为将若干个子管道中的数据全都,平面展开到父管道中进行处理。
            words.stream()
            .flatMap(w -> Arrays.stream(w.split("")))
            .forEach(System.out::println);
        }
    }
    

    2.2、有状态操作

    2.2.1、distinct(去重)
    // distinct方法时,调用Object的equals方法进行对象的比较。
    // 如果你有自己的比较规则,可以重写equals方法。
    // 经过管道处理之后的数据是: ["Monkey", "Lion", "Giraffe", "Lemur"]
    List<String> uniqueAnimals = Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
            .distinct()
            .collect(Collectors.toList());
    
    2.2.2、limit(取前N个)
    // limt方法传入一个整数n,用于截取管道中的前n个元素。
    // 经过管道处理之后的数据是:[Monkey, Lion]。
    List<String> limitN = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
            .limit(2)
            .collect(Collectors.toList());
    
    2.2.3、skip(跳过前N个)
    // skip方法与limit方法的使用相反,用于跳过前n个元素,截取从n到末尾的元素。
    // 经过管道处理之后的数据是: [Giraffe, Lemur]
    List<String> skipN = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
            .skip(2)
            .collect(Collectors.toList());
    
    2.2.4、sorted(排序)
    • 基本使用

      // 默认的情况下,sorted是按照字母的自然顺序进行排序。
      // 如下代码的排序结果是:[Giraffe, Lemur, Lion, Monkey]
      // 字数按顺序G在L前面,L在M前面。第一位无法区分顺序,就比较第二位字母。
      List<String> alphabeticOrder = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
              .sorted()
              .collect(Collectors.toList());
      
    • 像使用sql一样排序集合

      • 排序器

        // java8以前
        Collections.sort();
        
        // java8以后
        List<T> list = Arrays.asList();
        // Comparator<T> 排序器
        list.sort(Comparator<T>);
        
        // JDK默认定义的排序规则
        // 例如:
        // 大小写不敏感
        list.sort(String.CASE_INSENSITIVE_ORDER);
        // 自然顺序
        list.sort(Comparator.naturalOrder());
        
      • 对象排序

        public class Employee {
            private Integer id;
            private Integer age;
            private String gender;
            private String firstName;
            private String lastName;
            
            // 省略get set 构造 toString()
        }
        
        public class SortList {
            public static void main(String[] args){
                Employee e1 = new Employee(1,23,"M","Rick","Beethovan");
                Employee e2 = new Employee(2,13,"F","Martina","Hengis");
                Employee e3 = new Employee(3,43,"M","Ricky","Martin");
                Employee e4 = new Employee(4,26,"M","Jon","Lowman");
                Employee e5 = new Employee(5,19,"F","Cristine","Maria");
                Employee e6 = new Employee(6,15,"M","David","Feezor");
                Employee e7 = new Employee(7,68,"F","Melissa","Roy");
                Employee e8 = new Employee(8,79,"M","Alex","Gussin");
                Employee e9 = new Employee(9,15,"F","Neetu","Singh");
                Employee e10 = new Employee(10,45,"M","Naveen","Jain");
        
                List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
                
                // 先是按性别的倒序排序,再按照年龄的倒序排序
                employees.sort(
                    Comparator.comparing(Employee::getGender)
                    .thenComparing(Employee::getAge)
                    .reversed()
        		);
                
                // 打印
                employees.forEach(System.out::println);
                
                // 与sql的区别:
                //		都是正序 ,不加reversed
                //		都是倒序,最后面加一个reserved
                //		先是倒序(加reserved),然后正序
                //		先是正序(加reserved,负负得正),然后倒序(加reserved)
        
            }
        }
        

    3、Stream终端操作

    1、ForEach和ForEachOrdered

    // 如果我们只是希望将Stream管道流的处理结果打印出来,而不是进行类型转换。
    // 我们就可以使用forEach()方法或forEachOrdered()方法。
    
    Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
            .parallel()
            .forEach(System.out::println);
    
    Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
            .parallel()
            .forEachOrdered(System.out::println); // 按顺序输出
    
    • parallel()函数表示对管道中的元素进行并行处理,而不是串行处理,这样处理速度更快。
      • 无法保证顺序: 可能导致管道流中后面的元素先处理,前面的元素后处理。
    • forEachOrdered
      • 虽然在数据处理顺序上可能无法保障,但是forEachOrdered方法可以在元素输出的顺序上保证与元素进入管道流的顺序一致。

    2、collect(元素的收集)

    2.1、收集为Set
    // 通过Collectors.toSet()方法收集Stream的处理结果,将所有元素收集到Set集合中。
    
    Set<String> collectToSet = Stream.of(
       "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
    ) 
    .collect(Collectors.toSet());
    
    // 最终collectToSet 中的元素是:[Monkey, Lion, Giraffe, Lemur],注意Set会去重。
    
    2.2、收集到List
    // 同样,可以将元素收集到List使用toList()收集器中。
    
    List<String> collectToList = Stream.of(
       "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
    ).collect(Collectors.toList());
    
    // 最终collectToList中的元素是: [Monkey, Lion, Giraffe, Lemur, Lion]
    
    3.3、通用的收集方式
    // 可以将数据元素收集到任意的Collection类型:即向所需Collection类型提供构造函数的方式。
    
    LinkedList<String> collectToCollection = Stream.of(
       "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
    ).collect(Collectors.toCollection(LinkedList::new));
    
    //最终collectToCollection中的元素是: [Monkey, Lion, Giraffe, Lemur, Lion]
    
    // 注意:以上代码中使用了LinkedList::new,实际是调用LinkedList的构造函数,将元素收集到Linked List。
    // 当然你还可以使用诸如LinkedHashSet::new和PriorityQueue::new将数据元素收集为其他的集合类型,这样就比较通用了。
    
    3.4、收集到Array
    // 通过toArray(String[]::new)方法收集Stream的处理结果,将所有元素收集到字符串数组中。
    
    String[] toArray = Stream.of(
       "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
    ) .toArray(String[]::new);
    
    //最终toArray字符串数组中的元素是: [Monkey, Lion, Giraffe, Lemur, Lion]
    
    3.5、收集到Map
    // Function.identity()方法,该方法很简单就是返回一个“ t -> t ”(输入就是输出的lambda表达式)
    // distinct()来确保Map键值的唯一性
    
    Map<String, Integer> toMap = Stream.of(
        "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
    )
    .distinct()
    .collect(Collectors.toMap(
           Function.identity(),   // 元素输入就是输出,作为key
           s -> (int) s.chars().distinct().count()// 元素的长度,作为value
    ));
    
    // 最终toMap的结果是: {Monkey=6, Lion=4, Lemur=5, Giraffe=6}   
    
    3.6、groupingBy(分组收集)
    Map<Character, List<String>> groupingByList =  Stream.of(
        "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
    )
    .collect(Collectors.groupingBy(
           s -> s.charAt(0) ,  // 根据元素首字母分组,相同的在一组
           // counting()       // 加上这一行代码可以实现分组统计
    ));
    
    // 最终groupingByList内的元素: {G=[Giraffe], L=[Lion, Lemur, Lion], M=[Monkey]}
    //如果加上counting() ,结果是:  {G=1, L=3, M=1}
    
    // 这是以上代码过程的说明:groupingBy第一个参数作为分组条件,第二个参数是子收集器。
    
    3.7、其他常用方法
    // 判断管道中是否包含2,结果是: true
    boolean containsTwo = IntStream.of(1, 2, 3).anyMatch(i -> i == 2);
    
    // 统计元素个数:4
    long nrOfAnimals = Stream.of(
        "Monkey", "Lion", "Giraffe", "Lemur"
    ).count();
    
    // 管道中元素数据累加结果:sum: 6
    int sum = IntStream.of(1, 2, 3).sum();
    
    //管道中元素数据平均值:average: OptionalDouble[2.0]
    OptionalDouble average = IntStream.of(1, 2, 3).average();
    
    //管道中元素数据最大值:max: 3
    int max = IntStream.of(1, 2, 3).max().orElse(0);
    
    // 全面的统计结果statistics: IntSummaryStatistics{count=3, sum=6, min=1, average=2.000000, max=3}
    IntSummaryStatistics statistics = IntStream.of(1, 2, 3).summaryStatistics();
    

    4、Stream查找与匹配元素

    4.1、anyMatch

    public class Employee {
        private Integer id;
        private Integer age;
        private String gender;
        private String firstName;
        private String lastName;
        
        // 省略get set 构造 toString()
    }
    
    public class MatchFind {
        public static void main(String[] args){
            
            Employee e1 = new Employee(1,23,"M","Rick","Beethovan");
            Employee e2 = new Employee(2,13,"F","Martina","Hengis");
            Employee e3 = new Employee(3,43,"M","Ricky","Martin");
            Employee e4 = new Employee(4,26,"M","Jon","Lowman");
            Employee e5 = new Employee(5,19,"F","Cristine","Maria");
            Employee e6 = new Employee(6,15,"M","David","Feezor");
            Employee e7 = new Employee(7,68,"F","Melissa","Roy");
            Employee e8 = new Employee(8,79,"M","Alex","Gussin");
            Employee e9 = new Employee(9,15,"F","Neetu","Singh");
            Employee e10 = new Employee(10,45,"M","Naveen","Jain");
    
            List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
            
            // 查找员工列表中是否包含年龄大于70的员工
            
            // 传统写法
            boolean isExistAgeThan70 = false;
            for(Employee employee:employees){
              if(employee.getAge() > 70){
                isExistAgeThan70 = true;
                break;
              }
            }
            System.out.println(isExistAgeThan70);
            
            // lambda写法
            // .anyMatch():判断Stream流中是否包含某一个“匹配规则”的元素
            // 只要包含一个“匹配规则”的元素,就返回true
            isExistAgeThan70 = employees.steam().anyMatch(e -> e.getAge() > 70);
        }
    }
    

    4.2、allMatch

    // .allMatch():判断是够Stream流中的所有元素都符合某一个"匹配规则"
    // 所有元素都符合某一个"匹配规则",才返回true
    boolean isExistAgeThan10 = employees.stream().allMatch(e -> e.getAge() > 10);
    

    4.3、noneMatch

    // 判断是否Stream流中的所有元素都不符合某一个"匹配规则"
    // 所有元素都不符合某一个"匹配规则",才返回true
    boolean isExistAgeLess18 = employees.stream().noneMatch(e -> e.getAge() < 18);
    

    4.4、Optional

    // findFirst用于查找第一个符合“匹配规则”的元素,返回值为Optional
    // findAny用于查找任意一个符合“匹配规则”的元素,返回值为Optional
    
    // 从列表中按照顺序查找第一个年龄大于40的员工。
    Optional<Employee> employeeOptional
            =  employees.stream().filter(e -> e.getAge() > 40).findFirst();
    System.out.println(employeeOptional.get());
    
    // Optional类代表一个值存在或者不存在。在java8中引入,这样就不用返回null了。
    // 		如果存在,调用get()方法获取。
    //		如果不存在,调用get()方法,抛出异常。
    
    
    • get()。如果存在,获取值。如果不存在,抛出异常。

    • isPresent() 方法。存在返回true,不存在返回false

      boolean is =  employees.stream().filter(e -> e.getAge() > 40).findFirst().isPresent();
      System.out.println(is);
      
    • ifPresent(Consumer block)。会在值存在的时候执行给定的代码块。

      employees.stream().filter(e -> e.getAge() > 40).findFirst().ifPresent(e -> System.out.println(e));
      
    • orElse。如果不存在值,给一个默认值

      employees.stream().filter(e -> e.getAge() > 40).findFirst()
          .orElse(new Employee(0,0,"F","",""));
      

    5、Stream集合元素归约

    Stream.reduce,用来实现集合元素的归约.

    reduce函数有三个参数:

    • Identity标识:一个元素,它是归约操作的初始值,如果流为空,则为默认结果。
    • Accumulator累加器:具有两个参数的函数:归约运算的部分结果和流的下一个元素。
      • 阶段累加结果作为累加器的第一个参数
      • 集合遍历元素作为累加器的第二个参数
    • Combiner合并器(可选):当归约并行化时,或当累加器参数的类型与累加器实现的类型不匹配时,用于合并归约操作的部分结果的函数。

    5.1、Integer类型规约

    // reduce初始值为0,累加器可以是lambda表达式,也可以是方法引用。
    
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
    
    Integer total = numbers
            .stream()
            .reduce(0, (subtotal, element) -> subtotal + element);
    System.out.println(total);  //21
    
    Integer result = numbers
            .stream()
            .reduce(0, Integer::sum);
    System.out.println(result); //21
    

    5.2、String类型归约

    // 不仅可以归约Integer类型,只要累加器参数类型能够匹配,可以对任何类型的集合进行归约计算。
    
    List<String> letters = Arrays.asList("a", "b", "c", "d", "e");
    
    String res = letters
            .stream()
            .reduce("", (partialString, element) -> partialString + element);
    System.out.println(res);  // abcde
    
    
    String result = letters
            .stream()
            .reduce("", String::concat);
    System.out.println(result);  // abcde
    

    5.3、复杂对象归约

    Employee e1 = new Employee(1,23,"M","Rick","Beethovan");
    Employee e2 = new Employee(2,13,"F","Martina","Hengis");
    Employee e3 = new Employee(3,43,"M","Ricky","Martin");
    Employee e4 = new Employee(4,26,"M","Jon","Lowman");
    Employee e5 = new Employee(5,19,"F","Cristine","Maria");
    Employee e6 = new Employee(6,15,"M","David","Feezor");
    Employee e7 = new Employee(7,68,"F","Melissa","Roy");
    Employee e8 = new Employee(8,79,"M","Alex","Gussin");
    Employee e9 = new Employee(9,15,"F","Neetu","Singh");
    Employee e10 = new Employee(10,45,"M","Naveen","Jain");
    
    List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
    
    // 计算每个员工的年龄之和
    Integer total = employees.stream()
        // 先用map将Stream流中的元素由Employee类型处理为Integer类型(age)。
        .map(Employee::getAge)
        // 然后对Stream流中的Integer类型进行归约
        .reduce(0,Integer::sum);
    System.out.println(total); //346
    

    5.4、Combiner合并器的使用

    // 在进行并行流计算的时候,可能会将集合元素分成多个组计算。
    // 为了更快的将分组计算结果累加,可以使用合并器。
    
    Integer total2 = employees
        // 并行流
            .parallelStream()
        // 获取每个员工年龄
            .map(Employee::getAge)
        // 对Stream流中的Integer类型进行归约
            .reduce(0,Integer::sum,Integer::sum);  //注意这里reduce方法有三个参数
    
    System.out.println(total); //346
    
    // 因为Stream流中的元素是Employee,累加器的返回值是Integer,所以二者的类型不匹配。
    // 这种情况下可以使用Combiner合并器对累加器的结果进行二次归约,相当于做了类型转换。
    
    Integer total3 = employees.stream()
            .reduce(0,(totalAge,emp) -> totalAge + emp.getAge(),Integer::sum); //注意这里reduce方法有三个参数
    System.out.println(total); //346
    

    三、函数式接口

    1、特点

    • 接口有且仅有一个抽象方法
    • 允许定义静态非抽象方法
    • 允许定义默认defalut非抽象方法(default方法也是java8才有的)
      • 在java8之前,如果一个接口存在多个实现类。如果接口中添加新方法,实现类都要去修改一遍,继承该方法。
      • 在java8中,用defalut关键字定义一个方法,其接口的实现类就不需要继承该方法,使用时调用即可。
      • defalut关键字,还可以在函数式接口中定义非抽象方法,既有方法体。
    • 允许java.lang.Object中的public方法
    • @FunctionInterface注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。
      • 加上该注解能够更好地让编译器进行检查。
      • 如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。

    2、自定义Comparator排序

    // 传统写法
    employees.sort(new Comparator<Employee>() {
        @Override
        public int compare(Employee em1, Employee em2) {
            if(em1.getAge() == em2.getAge()){
                return 0;
            }
            return em1.getAge() - em2.getAge() > 0 ? -1:1;
        }
    });
    employees.forEach(System.out::println);
    
    // lambda写法
    employees.sort((em1,em2) -> {
        if(em1.getAge() == em2.getAge()){
            return 0;
        }
        return em1.getAge() - em2.getAge() > 0 ? -1:1;
    });
    employees.forEach(System.out::println);
    

    本篇文章学习自 字母哥-《恕我直言:你可能真的不会JAVA系列》。

  • 相关阅读:
    mac下xcode中include path
    如何联机调试和发布程序
    Facebook 错误码
    app store给应用评分功能
    FTP传输模式
    重新安装 Visual Studio 6.0 的问题
    ASP项目:提示用户 'NT AUTHORITY\NETWORK SERVICE' 登录失败
    投资项目的4P
    .net 的资源与本地化
    千万不能干的事(文摘)
  • 原文地址:https://www.cnblogs.com/luckyzs/p/13172453.html
Copyright © 2011-2022 走看看