day_25 JDK1.8新特性

JDK1.8新特性
1.Lambad表达式
    1.1 介绍
        是一种没有名字的函数,也可以称为闭包
        本质上是一段匿名内部类,也可以是一段可以传递的代码,还有叫箭头函数的

    闭包:
        能够读取其他函数内部变量的函数,比如在Java中,方法内部的局部变量只能
        在方法内部使用,本质就是将函数内部和外部链接起来的桥梁

    1.2 特点
        允许把函数作为一个方法的参数,
        使用Lambda表达式可以是代码变得更加简洁紧凑

    1.2 和匿名内部类对比
        //asList:把数组转换为List集合
        List<Integer> integer = Arrays.asList(arr);
        //匿名内部类写法
        Collections.sort(integers, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
            return o2 - o1;
            }
        });
        // lambda
        Collections.sort(integers, (i1, i2) -> i2 - i1);
        System.out.println(integers);

    1.3应用场景
        列表迭代
        Map映射
        Reduce聚合
        代替一个不想命名的函数或是类,该函数或类往往并不复杂

    1.4 代码实现
        特点:
            可选类型声明:不需要声明参数类型,编译器何以统一识别参数值
            可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号
            可选的大括号:如果主体包含了一个语句,就不需要使用大括号
            可选的返回关键字:如果主题只有一个表达式返回值则编译器会自动返回值,
             大括号需要指定明表达式返回了一个数值
                如果只有一条语句,并且是返回值语句,就可以不写return 不写{}
                如果写上{},就必须写return和;
                如果有多条语句,必须写{} return 和 ;

        *简单说明:
            // 1. 不需要参数,返回值为 5  
            () -> 5  

            // 2. 接收一个参数(数字类型),返回其2倍的值  
            x -> 2*x  

            // 3. 接受2个参数(数字),并返回他们的差值  
            (x, y) -> x – y  

            // 4. 接收2个int型整数,返回他们的和  
            (int x, int y) -> x + y  

            // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
            (String s) -> System.out.print(s)

        集合遍历:
            list.forEach(x->{ System.out.println(x);})
        集合排序:
            list.sort(new Comparator<Integer>(){
                public int compare(Integer o1,Integer o2){
                    return o1 - o2;
                }
            })

            list = Arrays.asList(arr);
            list.sort((x,y)->x-y);
            System.out.println(list);

2.函数式接口
    2.1 介绍:
        本质是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口
        核心目标是为了给Lambda表达式的使用提供更好的支持,提高效率

    2.2 回调函数:
        方法的参数是一个方法,在这个方法中对传递的方法进行调用

    2.3 应用场景
        想通过函数式编程,提高编程效率的各种场景均可

    2.4 代码实现
        2.4.1 无参情况
            public class FunInterface_01 {
                // 自定义静态方法,接收接口对象
                public static void call(MyFunctionInter func) {
                    // 调用接口内的成员方法
                    func.printMessage();
                }

                public static void main(String[] args) {
                    // 第一种调用 : 直接调用自定义call方法,传入函数
                    FunInterface_01.call(() -> {
                        System.out.println("HelloWorld!!!");
                    });

                    // 第二种调用 : 先创建函数对象,类似于实现接口的内部类对象
                    MyFunctionInter inter = () -> {
                        System.out.println("HelloWorld2!!!!");
                    };
                    // 调用这个实现的方法
                    inter.printMessage();
                }
            }
            // 函数式接口
            @FunctionalInterface
            interface MyFunctionInter {
                void printMessage();
            }

        2.4.2 有参情况
            public class FunInterface_02 {
                // 自定义静态方法,接收接口对象
                public static void call(MyFunctionInter_02 func, String message) {
                    // 调用接口内的成员方法
                    func.printMessage(message);
                }

                public static void main(String[] args) {
                    // 调用需要传递的数据
                    String message = "有参函数式接口调用!!!";

                    // 第一种调用 : 直接调用自定义call方法,传入函数,并传入数据
                    FunInterface_02.call((str) -> {
                        System.out.println(str);
                    }, message);

                    // 第二种调用 : 先创建函数对象,类似于实现接口的内部类对象
                    MyFunctionInter_02 inter = (str) -> {
                        System.out.println(str);
                    };
                    // 调用这个实现的方法
                    inter.printMessage(message);
                }
            }

            // 函数式接口
            @FunctionalInterface
            interface MyFunctionInter_02 {
                void printMessage(String message);
            }

    2.5 JDK自带常用的函数式接口
        2.5.1 Supplier<T>接口
            Supplier<T>接口    代表结果供应商,所以有返回值,可以获取数据
            有一个get方法,用于获取数据

        2.5.2 Consumer<T>接口  消费者接口 不需要返回值,有一个accept(T)方法,
                用于执行消费操作,可以对给定的参数T做任意操作

        2.5.3 Function<T,R>接口 
            表示接收一个参数并产生结果的函数有一个R apply(T)方法,Function中没有具体的操作,
            具体的操作需要我们去为它指定,因此apply具体返回的结果取决于传入的lambda表达式

        2.5.4 Predicate<T>接口 
            断言接口,返回值为boolean,有一个boolean test(T)方法,用于校验传入数据是否符合判断条件,返回boolean类型

3.方法引用和构造器调用
    3.1概念说明
        Lambda表达式的另外一种表现形式,提高方法复用率和灵活性。

    3.2 应用场景:  
        若Lambda 体中的功能,已经有方法提供了实现,可以使用方法引用。          
        不需要再复写已有API的Lambda的实现。

    3.4代码实现:
        1.对象的引用::实例方法名
        Integer intObj = new Integer(123456);
        // 常规lambda写法
        Supplier<String> su = () -> intObj.toString();
        System.out.println(su.get());

        // 方法引用写法
        Supplier<String> su1 = intObj::toString;
        System.out.println(su1.get());

        2.类名::静态方法名
        // 常规lambda写法
        // 前两个泛型是参数类型,第三个是返回值类型
        BiFunction<Integer, Integer, Integer> bi = (x, y) -> Integer.max(x, y);
        int apply = bi.apply(10, 11);
        System.out.println(apply);
        
        // 方法引用写法
        BiFunction<Integer, Integer, Integer> bif = Integer::max;
        int apply2 = bif.apply(10, 11);
        System.out.println(apply2);

        3.类名::实例方法名
        // 常规lambda写法
        // 两个泛型都是参数类型
        BiPredicate<String, String> predicate = (x, y) -> x.equals(y);
        System.out.println(predicate.test("a", "a"));
        // 方法引用写法
        // 使用第一个参数调用成员方法把第二个参数传入
        // ::前面的类型 要和 第一个参数的类型一致
        BiPredicate<String, String> predicate2 = String::equals;
        System.out.println(predicate2.test("a", "b"));

    构造器调用:
        // 无参构造器
        // 常规lambda写法
        Supplier<Object> objSup = () -> new Object();
        System.out.println(objSup.get());
        
        // 方法引用写法
        Supplier<Object> s1 = Object::new;
        System.out.println(s1.get());

        // 有参构造器
        // 常规lambda写法
        Function<String, Integer> func = (x) -> new Integer(x);
        System.out.println(func.apply("123456"));
        
        // 方法引用写法
        Function<String, Integer> func2 = Integer::new;
        System.out.println(func2.apply("123456"));

4.Stream API 
    1.特点:             
        Stream 不是数据结构,没有内部存储,自己不会存储元素。               
        Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。               
        Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。               
        不支持索引访问。               
        延迟计算               
        支持并行               
        很容易生成数据或集合               
        支持过滤,查找,转换,汇总,聚合等操作。

    2.运行机制说明
        Stream分为源source,中间操作,终止操作。                
        流的源可以是一个数组,集合,生成器方法,I/O通道等等。              
        一个流可以有零个或多个中间操作,每一个中间操作都会返回一个新的流,供下一个操作使用,一个流只会有一个终止操作。          
        中间操作也称为转换算子-transformation              
        Stream只有遇到终止操作,它的数据源会开始执行遍历操作。               
        终止操作也称为动作算子-action
        因为动作算子的返回值不再是 stream,所以这个计算就终止了
        只有碰到动作算子的时候,才会真正的计算

    3.生成stream流的五种方式说明
        // 1 通过数组,Stream.of()
        String[] str = { "a", "b", "c" };
        Stream<String> str1 = Stream.of(str);
        // System.out.println(str1);

        // 2 通过集合
        List<String> strings = Arrays.asList("a", "b", "c");
        Stream<String> stream = strings.stream();
        System.out.println(stream);

        // 3 通过Stream.generate方法来创建
        // 这是一个无限流,通过这种方法创建在操作的时候最好加上limit进行限制
        Stream<Integer> generate = Stream.generate(() -> 1);
        generate.limit(10).forEach(x -> System.out.println(x));

        // 4 通过Stream iterate
        Stream<Integer> iterate = Stream.iterate(1, x -> x + 2);
        iterate.limit(100).forEach(x -> System.out.println(x));

        // 5 已有类的stream源生成API
        String str2 = "123456";
        IntStream chars = str2.chars();
        chars.forEach(x -> System.out.println(x));

    4.常用转换算子
        常用转换算子 filter,distinct,map,limit,skip,flatMap等
  
        filter : 对元素进行过滤筛选,不符合的就不要了
                
        distinct : 去掉重复的元素
        
        skip : 跳过多少元素
        
        limit : 取一个集合的前几条数据
        
        map : 
                可以理解是在遍历集合的过程中,对元素进行操作,比如判断集合元素是否是a 返回boolean
                因为 map的返回值,就是新集合中的元素,所以也可以在遍历的时候对集合的数据进行更改,比如都加 --
                
        flatMap : 解决一个字符串数组  返回单一的字符串使用flatMap
        本来集合中有两个数组,可以通过flatMap 把数组中的每一个元素都放到集合中,然后把数组去掉
        
        注意只用此算子是不会真正进行计算的,只有后边调用动作算子才会真正计算。

        List<String> strings = Arrays.asList("a", "b", "c", "a");
        Stream<String> stream = strings.stream();
        /**
         * 对元素进行过滤筛选,不符合的就不要了
         */
        // collect 把符合条件的转换为集合strings,属于动作算子,因为不用动作算子这些转换算子不会执行,所以看不到结果
        // 只要 a
        List<String> value  = stream.filter(x -> x.equals("a")).collect(Collectors.toList());
        // 集合中只有 a 了
        System.out.println(value);
        
        // 使用过之后,需要重新生成stream
        stream = strings.stream();
        /**
         *  跳过1个元素 原来是 abca 现在就是 bca
         */
        value = stream.skip(1).collect(Collectors.toList());
        // bca
        System.out.println(value);
        
        /**
         *  map : 可以理解是在遍历集合的过程中,对元素进行操作,比如判断集合元素是否是a 返回boolean
         *          或者对集合元素进行更改数据,比如都加--
         */
        stream = strings.stream();
        // 判断集合元素,这样就是booelean 是a 就是true 否则就是false
        List<Boolean> value1=stream.map(x -> x.equals("a")).collect(Collectors.toList());
        // true,false,false,true
        System.out.println(value1);
        
        stream = strings.stream();
        // 更改集合元素
        value =stream.map(x -> x+"--").collect(Collectors.toList());
        // a--, b--, c--, a--
        System.out.println(value);
        /**
         * 去掉重复元素
         */
        stream = strings.stream();
        value = stream.distinct().collect(Collectors.toList());
        // 去除一个a 只有a,b,c
        System.out.println(value);

        /**
         * 取一个集合的前几条数据
         */
        stream = strings.stream();
        value = stream.limit(2).collect(Collectors.toList());
        // ab
        System.out.println(value);
        
        /**
         * 解决一个字符串数组  返回单一的字符串使用flatMap
         */
        strings = Arrays.asList("1,2,3", "a,b,c");
        stream = strings.stream();
        // 本来集合中有两个数据 "1,2,3" 和 "a,b,c"
        // 会把每一个元素 以 , 分割,得到字符串数组
        // 然后把数组中每一个元素,都单独拿出来
        // 最终就会得到 1,2,3,a,b,c 6个元素  
        // 通过 collect 把这6个元素 放到集合中
        value =stream.map(x -> x.split(",")).flatMap(arr -> Arrays.stream(arr)).collect(Collectors.toList());
        // 1, 2, 3, a, b, c
        System.out.println(value);

    5.常用动作算子
        循环 forEach
     
        计算 min、max、count、average
            
        匹配 anyMatch、allMatch、noneMatch、findFirst、findAny

        汇聚 reduce
            
        收集器 collect

5.接口中的默认方法和静态方法
    1.特点:    
        默认方法             
        可以被重写,也可以不重写。如果重写的话,就按实现类的方法来执行。                    
        调用的时候必须是实例化对象调用。               
        静态方法                   
        跟之前的普通类的静态方法大体相同                   
        唯一不同的是不能通过接口的实现类的对象来调用,必须是类.静态方法的方式。

    2.代码实现
        public static void main(String[] args) {
                MyInter inter = new MyInterImpl();
                System.out.println(inter.add(3, 4));
                inter.printMessage();
            }
        }

        interface MyInter {
            // 之前的用法
            int add(int i, int j);

            // 新加的默认方法
            default void printMessage() {
                System.out.println("在接口中的默认实现");
            }
        }

        class MyInterImpl implements MyInter {
            @Override
            public int add(int i, int j) {
                return i + j;
            }

            @Override
            public void printMessage() {
                System.out.println("在接口的实现类中的默认实现");
            }
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值