• 2、四大核心函数式接口


    1、 函数式接口

    1.1 概念

    函数式接口是只有一个方法的接口,用作lambda表达式的类型。

    具体就是说,注解在Inteface上,且interface里只能有一个抽象方法,可以有default方法。

    因为从语义上来讲,一个函数式接口需要通过一个逻辑上的方法表达一个单一函数。那理解这个单一就很重要了,单一不是说限制你一个interface里只有一个抽象方法,单一是多个方法的其他方法需要是继承自Objectpublic方法,或者你要想绕过,就自己实现default

    函数式接口自己本身一定是只有一个抽象方法。同时,如果是Object类的public方法,也是不允许的

    前面写的例子就是一个函数式接口,来看看jdk中的Runnable源码

    
    
    @FunctionalInterface
    public interface Runnable {
        /**
         * When an object implementing interface <code>Runnable</code> is used
         * to create a thread, starting the thread causes the object's
         * <code>run</code> method to be called in that separately executing
         * thread.
         * <p>
         * The general contract of the method <code>run</code> is that it may
         * take any action whatsoever.
         *
         * @see     java.lang.Thread#run()
         */
        public abstract void run();
    }
    
       
    

    这里只有一个抽象方法run,实际上你不写public abstract也是可以的,在接口中定义的方法都是public abstract的。 同时也使用注解@FunctionalInterface告诉编译器这是一个函数式接口,当然你不这么写也可以,标识后明确了这个函数中 只有一个抽象方法,当你尝试在接口中编写多个方法的时候编译器将不允许这么干。

    1.2 例子

    @FunctionalInterface
    public interface Demo5 {
    
    }
    

    这样编译器肯定是报错的,会显示没有target method,因为函数式接口必须要又一个抽象方法;


    @FunctionalInterface
    public interface Demo5 {
        void run();
    }
    

    这个时候,一个函数式接口就Ok了;


    @FunctionalInterface
    public interface Demo5 {
        void run();
        void go();
    }
    

    编译器报错Multiple non-overriding abstract methods found in interface,因为函数式接口只可以有一个抽象方法;


    @FunctionalInterface
    public interface Demo5 {
        boolean equals(Object obj);
    }
    
    

    编译器报错no target method,因为equals方法是Object类的public


    @FunctionalInterface
    public interface Demo5 {
        @Override
        boolean equals(Object obj);
    
        void run();
    }
    

    一个抽象方法,一个Object的public方法,相安无事


    @FunctionalInterface
    public interface Demo5 {
        Object clone();
        void run();
    }
    

    编译器报错,因为clone()Object类里面protected方法


    @FunctionalInterface
    public interface Demo5 {
    
        void run();
    
        /**
         * 非静态方法
         */
        default void test() {
            System.out.println("我是 default方法");
        }
    
        /**
         * 静态方法
         */
        public static void test2() {
            System.out.println("333");
        }
    }
    

    这也是一个合格的函数式接口,因为从java8开始,接口中可以存在静态方法(只可以是public修饰)和非静态方法(只可以使default修饰)

    1.3 四种函数式接口

    接口 | 参数 | 返回值 | 示例 | 类别
    ---|---|---|---|---|---|---
    Consumer | T | void | 输出一个值|消费型接口
    Supplier | None | T | 工厂方法 | 工厂方法
    Function | T | R | 获得Artist对象的名字|函数型接口
    Predicate | T | boolean | 这张唱片已经发行了吗|断言型接口

    消费型接口

    
        public static void donation(Integer money, Consumer<Integer> consumer) {
            consumer.accept(money);
        }
        
        donation(100, x -> System.out.println("捐赠了:" + x));
        
    

    供给型接口

    // 产生一些整数放到集合中
    public static List<Integer> supply(Integer num, Supplier<Integer> supplier) {
            List<Integer> list = new ArrayList<>();
            for (int x = 0; x <= num; x++) {
                list.add(supplier.get());
            }
            return list;
        }
        
    List<Integer> list = supply(10, () -> (int) (Math.random() * 1000));
    

    函数型接口

    public static Integer convert(String str, Function<String, Integer> function) {
            return function.apply(str);
        }
        
    Integer a = convert("12", x -> Integer.parseInt(x));
    

    断言型接口

    // 将满足条件的字符串放到集合中
    public static List<String> filter(List<String> fruits, Predicate<String> predicate) {
            List<String> resultList = new ArrayList<>();
            for (String item : fruits) {
                if (predicate.test(item)) {
                    resultList.add(item);
                }
            }
            return resultList;
        }
        
    List<String> list1 = new ArrayList<>();
            list1.add("苹果");
            list1.add("香蕉");
            list1.add("西瓜");
            list1.add("西红柿");
    List<String> f = filter(list1, x -> x.length() == 2);
    
    
    

    3.4 默认方法

    Java语言中,一个接口中定义的方法必须由实现类提供实现。但是当接口中加入新的API时, 实现类按照约定也要修改实现,而Java8API对现有接口也添加了很多方法,比如List接口中添加了sort方法。 如果按照之前的做法,那么所有的实现类都要实现sort方法,JDK的编写者们一定非常抓狂

    幸运的是我们使用了Java8,这一问题将得到很好的解决,在Java8种引入新的机制,支持在接口中声明方法同时提供实现。 这令人激动不已,你有两种方式完成:

    1.在接口内声明静态方法

    2.指定一个默认方法

    default void sort(Comparator<? super E> c) {
            Object[] a = this.toArray();
            Arrays.sort(a, (Comparator) c);
            ListIterator<E> i = this.listIterator();
            for (Object e : a) {
                i.next();
                i.set((E) e);
            }
        }
    

    翻阅List接口的源码,其中加入一个默认方法default void sort(Comparator<? super E> c)

    在返回值之前加入default关键字,有了这个方法我们可以直接调用sort方法进行排序

    List<Integer> list = Arrays.asList(2, 7, 3, 1, 8, 6, 4);
    list.sort(Comparator.naturalOrder());
    System.out.println(list);
    

    Comparator.naturalOrder()是一个自然排序的实现,这里可以自定义排序方案。你经常看到使用Java8操作集合的时候可以直接foreach的原因也是在Iterable接口中也新增了一个默认方法:forEach,该方法功能和 for 循环类似,但是允许 用户使用一个Lambda表达式作为循环体。

    一个小小的程序员
  • 相关阅读:
    java 网络编程
    JAVA 中for-each循环使用方法
    JAVA 常用集合接口List、Set、Map总结
    android学习计划
    ExtJs
    jQuery easyui
    MVC
    简易servlet计算器
    使用servlet实现用户注册功能
    用JavaBean实现数据库的连接和关闭,在jsp页面输出数据库中student表中学生的信息
  • 原文地址:https://www.cnblogs.com/zhaod/p/13437143.html
Copyright © 2020-2023  润新知