zoukankan      html  css  js  c++  java
  • Java8 Lambda

    Java8 函数式编程

    在思考问题时,使用不可变值和函数,函数对一个值进行处理,映射成另一个值。

    系统的功能应该更多的源自于程序之间的关系,而非程序本身。

    lambda表达式

    1. lambda 的几种形式
    Runnable noArg = () -> System.out.println("111");
    ActionListener oneArg = event -> System.out.println("222");
    Runnable multisStatemnet = () -> {
        System.out.println("333");
        System.out.println("444");
    };
    BinaryOperator<Long> add = (x, y) -> x * y;
    BinaryOperator<Long> addExp = (Long x, Long y) -> x + y;
    // 目标类型是指Lambda表达式所在上下文环境的类型。
    // lambda表达式的类型依赖上下文环境
    
    1. Lambda表达式是一个匿名方法,将行为像数据一样进行传递。
    2. 函数接口指仅具有单个抽象方法的接口,用来表示Lambda表达式的类型。
    3. 可以不再显式生命类型,Java8会进行类型推断。

    匿名内部类

    内部类创建表达式会确保在创建一个拥有唯一标识的新对象,而lambda可能有,也可能没有,这取决与具体表现,相对于内部类来说,这种灵活性可以让平台使用更为高效的实现策略。

    内部类的声明会创建出一个新的命名作用域,在这个作用域中,this和super指的是内部类本身的当前实例;相反lambda表达式并不会引入任何新的命名环境,这样避免了内部类名称查找的复杂性。

    如果数据的处理结果和顺序没有关系,那么可以采用并行的计算模型。

    1. 常用的流操作
    @Data
    @Builder
    public class Student {
    
        private String name;
        private Integer sex;
        private Integer age;
    }
    
    // 构建一个学生和课程成绩的关系,来测试lambda表达式                                                                                                                               
    List<Student> studentList = new ArrayList<>();                                       
    studentList.add(Student.builder().name("aa").age(11).sex(1).build());                 
    studentList.add(Student.builder().name("bb").age(12).sex(0).build());    
    studentList.add(Student.builder().name("cc").age(10).sex(1).build());                 
    studentList.add(Student.builder().name("dd").age(12).sex(0).build());                 
    studentList.add(Student.builder().name("ee").age(12).sex(1).build());                 
    studentList.add(Student.builder().name("ff").age(10).sex(0).build());                
    studentList.add(Student.builder().name("gg").age(11).sex(1).build());               
    studentList.add(Student.builder().name("hh").age(13).sex(1).build()); 
    studentList.add(Student.builder().name("ii").age(12).sex(0).build());        
    studentList.add(Student.builder().name("jj").age(11).sex(0).build());                                                                                                
    // 计算年龄最大的学生                                                                   
    Student ageMax = studentList.stream().max(Comparator.comparing(Student::getAge)).get();                                                                             
    System.out.println("年龄最大的学生为:" + ageMax.getName() + " 年龄为:" + ageMax.getAge());                                                                                     
    // 计算年龄最小的学生                                                                                                                                                        
    Student ageMin = studentList.stream().min(Comparator.comparing(Student::getAge)).get();
    System.out.println("年龄最小的学生为:" + ageMin.getName() + " 年龄为:" + ageMax.getAge());                                                                                     
    // 年龄大于10岁的学生的数量
    long gt10 = studentList.stream().filter(s -> s.getAge() > 10).count();
    System.out.println("年龄大于10岁的学生的数量:" + gt10);
    
    // 每一个年龄段的学生的数量
    Map<Integer, Long> collect = studentList.stream().collect(Collectors.groupingBy(Student::getAge, Collectors.counting()));                                           
    System.out.println("每个年龄段的学生的数量:" + collect);
    
    // 将学生按照性别分组
    Map<Integer, List<Student>> collect1 = studentList.stream().collect(Collectors.groupingBy(Student::getSex, Collectors.toList()));                                   
    System.out.println("将学生按照性别分组" + collect1);                                                                                                                         
    // 将学生按照性别分组后 只获取学生的姓名
    Map<Integer, Set<String>> collect2 = studentList.stream().collect(Collectors.groupingBy(Student::getSex, Collectors.mapping(Student::getName, Collectors.toSet())));
    System.out.println("将学生按照性别分组后,只取学生的姓名:" + collect2);                                                                                                               
    // 对所有的学生年龄+1
    List<Student> collect3 = studentList.stream().map(s -> {                             
        s.setAge(s.getAge() + 1);
        return s;
    }).collect(Collectors.toList());
    System.out.println("将所有学生年龄+1:" + collect3);                                                                                                                        
    // 将学生按照年龄进行排序
    List<Student> sorted = studentList.stream().sorted(Comparator.comparing(Student::getAge)).collect(Collectors.toList());                                             
    System.out.println("将学生按照年龄进行排序:" + sorted);
    
    // reduce 操作 将集合中的元素求和
    Optional<Integer> total = Stream.of(1, 2, 3, 4, 5).reduce((x, y) -> x + y);
    Integer total2 = Stream.of(1, 2, 3, 4, 5).reduce(0, (x, y) -> x + y);                                                                                               
    // 将 List 转为 Map
    List<Integer> collect4 = Stream.of(1, 2, 3, 4).collect(Collectors.toList());
    Map<Integer, Integer> collect5 = collect4.stream().collect(Collectors.toMap(x -> x, x -> x + 1, (x, y) -> y));                                                      
    System.out.println("list 转 Map:" + collect5);
    

    Collectors 类的静态工厂方法。

    工厂方法 返回类型 作用
    toList List 把流中所有项目收集到一个 List
    toSet Set 把流中所有项目收集到一个 Set,删除重复项
    toCollection Collection 把流中所有项目收集到给定的供应源创建的集合menuStream.collect(toCollection(), ArrayList::new)
    counting Long 计算流中元素的个数
    sumInt Integer 对流中项目的一个整数属性求和
    averagingInt Double 计算流中项目 Integer 属性的平均值
    summarizingInt IntSummaryStatistics 收集关于流中项目 Integer 属性的统计值,例如最大、最小、 总和与平均值
    joining String 连接对流中每个项目调用 toString 方法所生成的字符串collect(joining(", "))
    maxBy Optional 一个包裹了流中按照给定比较器选出的最大元素的 Optional, 或如果流为空则为 Optional.empty()
    minBy Optional 一个包裹了流中按照给定比较器选出的最小元素的 Optional, 或如果流为空则为 Optional.empty()
    reducing 归约操作产生的类型 从一个作为累加器的初始值开始,利用 BinaryOperator 与流 中的元素逐个结合,从而将流归约为单个值累加int totalCalories = menuStream.collect(reducing(0, Dish::getCalories, Integer::sum));
    collectingAndThen 转换函数返回的类型 包裹另一个收集器,对其结果应用转换函数int howManyDishes = menuStream.collect(collectingAndThen(toList(), List::size))
    groupingBy Map<K, List> 根据项目的一个属性的值对流中的项目作问组,并将属性值作 为结果 Map 的键
    partitioningBy Map<Boolean,List> 根据对流中每个项目应用谓词的结果来对项目进行分区

    Option 对象

    Optional<Integer> optional = Optional.of(1);             // 不允许值为null
    Optional<Integer> optional1 = Optional.ofNullable(null); // 允许值为null
    // 判断值是否存在 true 存在
    if (optional1.isPresent()) {
        // 获取存储的值,如果不存在,直接进行获取的话就报错
        optional1.get();
    }
    optional.ifPresent(i -> System.out.println("存在 " + i));
    
    optional1.orElse(100);
    

    数据并行化

    并发是两个任务共享时间段,并行是两个任务同一时间发生

    parallelStream()
    影响并行处理性能的因素 数据大小,元数据结构,装箱,可用cpu数量,处理每个元素的时间

    影响运行性能测试的一些原因

    1. 热身效应:代码在运行100次和运行1分钟时的测量效果不一样,JIT的编译问题。
    2. 无用代码消除:DEC是一个编译器优化技术,目的是消除无用代码。
    3. 垃圾收集:在进行垃圾回收时,也会影响性能测试。
    4. 时钟:在使用System.currentTimeMillis()时,会有几毫秒的误差。

    问题

    关于接口的默认方法

    接口A的默认方法为Stirng,接口B的默认方法为String,类C实现了A,B两个接口,此时需要实现String方法,否则就会出现钻石继承的问题。如果AB两个接口内的默认方法不冲突,则C不需要重新实现默认方法。

  • 相关阅读:
    VS2017离线安装与Oracle数据库开发环境搭建
    拒绝“高冷”词汇!初学C#中的委托
    拒绝“高冷”词汇!初学C#中实用的泛型!
    误删Django的model中的表解决办法
    Django-ORM操作
    请求头获取用户设备、点赞
    随机验证码、图片验证码和邮箱发送用户验证码
    Django的Form验证(2)
    Django的Form验证
    Pycharm导入Django项目
  • 原文地址:https://www.cnblogs.com/iFanLiwei/p/12805090.html
Copyright © 2011-2022 走看看