Java8新特性

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、Lambda表达式

1.1 概述

	Lambda表达式的使用:
  1. 举例:(o1,o2) -> Integer.compare(o1,o2);
  2. Lambda表达式的本质: 作为函数式接口的实例
  3. 格式:
    • ->:lambda操作符或箭头操作符
    • 左边:lambda形参列表(其实就是抽象方法的形参列表)
    • 右边:lambda体(其实就是重写的抽象方法的方法体)

1.2 语法格式

  • 语法格式一:无参数,无返回值
    //语法格式一:无参数,无返回值
    @Test
    public void test01(){
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("hello world");
            }
        };
//        r1.run();

        //使用lambda表达式
        Runnable r2 = ()-> System.out.println("hello girl");
        r2.run();
    }
  • 语法格式二:有参数,无返回值
    //语法格式二:有参数,无返回值
    @Test
    public void test02(){
        Consumer<String> con = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("人人为我我为人人");

        System.out.println("***********************************");

        //参数里的String类型可以省略,因为编译器可以做出”类型推断“
        //参数如果只有一个,那么参数的小括号也可以省略
        Consumer<String> con2 = s ->{
            System.out.println(s);
        };
        con.accept("你笑起来真好看");
    }
  • 语法格式三:有多个参数多条语句,有返回值
    @Test
    public void test04(){
        Comparator<Integer> com = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };
        System.out.println(com.compare(15, 20));

        System.out.println("============================================");

        Comparator<String> com2 = (s1,s2) ->{
            System.out.println(s1);
            System.out.println(s2);
            return s1.compareTo(s2);
        };
        System.out.println(com2.compare("a","b"));
    }
  • 语法格式四:当Lambda体只有一条语句时
    //语法格式四:当Lambda体只有一条语句时,return与大括号都可以省略
    @Test
    public void test05(){
        Comparator<Integer> com = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return -o1.compareTo(o2);
            }
        };

        System.out.println(com.compare(12, 50));

        System.out.println("==================================");

        Comparator<Integer> com2 = (o1,o2) -> -o1.compareTo(o2);
        System.out.println(com2.compare(15,10));
    }

1.3 总结

  • Lambda表达式的形参列表的参数类型可以省略(类型推断);如果Lambda形参列表只有一个参数,()也可以省略
  • Lambda体应该使用一对{}包裹;如果Lambda体只有一条执行语句(可能有返回值),return关键字与{}都可以省略(如果省略{}那么return关键字也必须省略)

二、函数式接口

2.1 概述

  • 只包含一个抽象方法的的接口,称为函数式接口
  • 你可以通过Lambda表达式创建该接口的对象(若Lambda表达式抛出一个受检异常(非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明
  • 我们可以在接口上使用@Fuctionallnterface 注解,这样做可以检查他是否是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口
  • java.util.fuction包下定义了丰富的函数式接口
  • 以前使用匿名实现类表示的现在都可以使用Lambda表达式来书写

2.2 Java内置函数式接口

  • 四大函数式接口
    在这里插入图片描述
  • 其他接口
    在这里插入图片描述

三、方法的引用与构造器的引用

3.1 方法引用(Method Reference)

  • 当要传递给Lambda体的操作,已经有了实现的方法,可以使用方法的引用
  • 方法引用可以看作是Lambda表达式深层次的表达,换句话说,方法的引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以把它作为Lambda表达式的语法糖
  • 要求:实现接口的抽象方法的参数类型和返回值类型,必须与方法引用的方法参数列表和返回值类型保持一致
  • 格式:使用操作符::将类(或对象)与方法名分隔开来
  • 三种主要使用情况:
    • 对象::实例方法名
    • 类::静态方法名
    • 类::实例方法名
  • 方法引用的使用要求:要求接口中的抽象方法的【形参列表】和【返回值类型】与【方法引用的方法】的【形参列表】和【返回值类型】相同

3.2 案例分析

  • 情况一:对象 :: 实例方法
//情况一:对象 :: 实例方法
    //Consumer中的void accept(T t)
    //PrintStream中的void println(T t)
    @Test
    public void test01(){
        //常规方式
        Consumer<String> con = str -> System.out.println(str);
        con.accept("hello world");

        System.out.println(line);
        //当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用
        PrintStream ps = System.out;
        Consumer<String> con2 = ps::println;
        con2.accept("我爱你中华!");
    }

    //Supplier中的T get()
    //Employee中的String getName()
    @Test
    public void test02(){
        //Lambda的常规用法
        Supplier<Integer> s = () ->10;
        System.out.println(s.get());

        System.out.println(line);
        Employee emp = new Employee(12, "张三", 10, 50000000);
        //对象 :: 实例方法
        Supplier<String> s2 = emp::getName;
        System.out.println(s2.get());
    }
  • 情况二:类 :: 静态方法
// 情况二:类 :: 静态方法
        //Comparator中的int compare(T t1,T t2)
        //Integer中的int compare(T t1,T t2)
        @Test
        public void test03(){
//            Comparator<Integer> com = (Integer i1,Integer i2) -> {
//                return Integer.compare(i1, i2);
//            };

            Comparator<Integer> com3 = (i1,i2) -> Integer.compare(i1, i2);
            System.out.println(com3.compare(10, 20));

            System.out.println(line);
        // 情况二:类 :: 静态方法
        Comparator<Integer> com2 = Integer::compare;
        System.out.println(com2.compare(112, 32));
        }


        //Function中的R apply(T t)
        //Math中的Long round(Double d)
        @Test
        public void test04(){
        Function<Double,Long> f = new Function<Double, Long>() {
            @Override
            public Long apply(Double aDouble) {
                return Math.round(aDouble);
            }
        };
        //Lambda表达式的写法
        Function<Double,Long> f2 = (aDouble) -> Math.round(aDouble);

        //方法的引用
        Function<Double,Long> f3 = Math::round;
            System.out.println(f3.apply(12.4));
        }
  • 情况三:类 :: 实例方法
    // 情况三:类 :: 实例方法  (有难度)
    // Comparator中的int compare(T t1,T t2)
    // String中的int t1.compareTo(t2)
    @Test
    public void test05(){
        Comparator<Integer> com = (i1,i2) -> i1.compareTo(i2);
        System.out.println(com.compare(10, 15));

        System.out.println(line);
        //类 :: 实例方法
        Comparator<String> com2 = String::compareTo;
        System.out.println(com2.compare("abc", "aph"));
    }

    //BiPredicate中的boolean test(T t1, T t2);
    //String中的boolean t1.equals(t2)
    @Test
    public void test06(){
        BiPredicate<String,String> b = (s1,s2) -> s1.equals(s2);
        System.out.println(b.test("abc", "abc"));

        System.out.println(line);
        BiPredicate<String,String> b2 = String::equals;
        System.out.println(b2.test("acb", "sbf"));
    }

四、强大的Stream API

4.1 Stream API概述

4.1.1 Stream API的说明

  • Java8中有两大最为重要的改变。第一个是 Lambda 表达式另外一个则是 Stream API
  • Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码
  • Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简言之,Stream API 提供了一种高效且易于使用的处理数据的方式

4.1.2 为什么要使用Stream API

  • 实际开发中,项目中多数数据源都来自于Mysql,Oracle等。但现在数据源可以更多了,有MongDB,Radis等,而这些NoSQL的数据就需要Java层面去处理。
  • Collection 和 Stream 集合的区别:Collection 是一种静态的内存数据结构,而 Stream 是有关计算的。前者是主要面向内存,存储在内存中,后者主要是面向 CPU,通过 CPU 实现计算

4.1.3 什么是Stream

是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
集合讲的是数据,Stream讲的是计算!

注意:

  • Stream 自己不会存储元素
  • Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream
  • Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行

4.1.4 Stream操作的三个步骤

  1. 创建 Stream:一个数据源(如:集合、数组),获取一个流
  2. 中间操作:一个中间操作链,对数据源的数据进行处理
  3. 终止操作(终端操作):一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
    在这里插入图片描述

4.2 创建Stream的方式

  • 创建 Stream方式一:通过集合
    //创建Stream方式一:通过集合
    @Test
    public void test01(){
        List<Employee> employees = EmployeeData.getEmployees();
        //default Stream<E> stream():返回一个顺序流
        Stream<Employee> stream = employees.stream();
        
        //default Stream parallelStream():返回一个并行流
        Stream<Employee> parallelStream = employees.parallelStream();
    }
  • 创建 Stream方式二:通过数组
    //创建Stream方式二:通过数组
    @Test
    public void test02(){
        int[] arr = new int[]{1, 2, 3, 4, 5, 6};
        IntStream stream = Arrays.stream(arr);

        Employee emp1 = new Employee(1, "dick");
        Employee emp2 = new Employee(2, "jack");
        Employee[] emps = new Employee[]{emp1,emp2};
        Stream<Employee> stream1 = Arrays.stream(emps);
    }
  • 创建 Stream方式三:通过Stream的of()
    //创建Stream方式三:通过Stream的of()
    @Test
    public void test03(){
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
    }
  • 创建 Stream方式四:创建无限流
    //创建Stream方式四:创建无限流
    @Test
    public void test04(){
        //遍历前十个数
        Stream.iterate(0, t -> t+ 2).limit(10).forEach(System.out::println);
    }

4.3 Stream 的中间操作

4.3.1 概述

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”

4.3.2 中间操作分类

  • 筛选与切片
    在这里插入图片描述
  • 案例分析:
//筛选与切片
    @Test
    public void test01(){
        List<Employee> list = EmployeeData.getEmployees();
        //从流中排除某些元素,找出工资大于7000的员工
        Stream<Employee> stream = list.stream();
        stream.filter(s -> s.getSalary() > 7000).forEach(System.out::println);
        //limit():截断流,是元素不超过给定的数量
        Stream<Employee> stream1 = list.stream();
        stream1.filter(s -> s.getSalary() > 5000).limit(2).forEach(System.out::println);
        //skip():跳过元素
        Stream<Employee> stream2 = list.stream();
        stream2.filter(s -> s.getSalary() > 5000).skip(2).forEach(System.out::println);
        //distinct():筛选去重
        Stream<Employee> stream3 = list.stream();
        stream3.filter(s -> s.getSalary() > 2000).distinct().forEach(System.out::println);
    }

  • 映 射
    在这里插入图片描述
  • 案例分析:


	@Test
    public void test03(){
        String[] str = new String[]{"aa","ss","dd","mm"};
        List<String> array = Arrays.asList(str);
        //通过map遍历
        Stream<Stream<Character>> streamStream = array.stream().map(StreamTest02::fromStringToStream);
        streamStream.forEach(s -> {
            s.forEach(System.out::println);
        });
        //flatMap(Function f)
        //接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
        Stream<Stream<Character>> streamStream2 = array.stream().map(StreamTest02::fromStringToStream);
        Stream<Character> characterStream = array.stream().flatMap(StreamTest02::fromStringToStream);
        characterStream.forEach(System.out::println);
    }
        //将字符串中的多个字符构成的集合转换为对应的Stream实例
        public static Stream<Character> fromStringToStream(String str){
            ArrayList<Character> list1 = new ArrayList<>();
            for (Character c : str.toCharArray()) {
                list1.add(c);
            }
            return list1.stream();
    }
  • 排序
  • 案例分析:
    //排序sort()
    @Test
    public void test05(){
        List<Employee> employees = EmployeeData.getEmployees();
        List<Integer> arrays = Arrays.asList(5, 8, 6, 3, 10, 25, 99, 21);
        //整型可以自然排序,因为其实现了Comparable接口
        arrays.stream().sorted().forEach(System.out::println);
        //Employee类没有实现Comparable接口,无法实现自然排序,只能定制排序
        //根据员工的年龄进行排序
        employees.stream().sorted((s1,s2) -> {
            int com1 = Integer.compare(s1.getAge(), s2.getAge());
            if (com1 != 0){
                return com1
            }else {
                return Double.compare(s1.getSalary(), s2.getSalary());
            }
        }).forEach(System.out::println);
    }
    }

4.4 Stream 的终止操作

4.4.1 概述

  • 终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void
  • 流进行了终止操作后,不能再次使用

4.4.2 终止操作的分类

  1. 匹配与查找
    在这里插入图片描述
    在这里插入图片描述

  2. 归约
    在这里插入图片描述

  3. 收集
    在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值