目录
1, 函数式接口
1.1 概念
1.2 例子
1.3 四种函数式接口
消费型接口
供给型接口
函数型接口
断言型接口
3.4 默认方法
1, 函数式接口
1.1 概念
函数式接口是只有一个方法的接口, 用作 lambda 表达式的类型.
具体就是说, 注解在 Inteface 上, 且 interface 里只能有一个抽象方法, 可以有 default 方法.
因为从语义上来讲, 一个函数式接口需要通过一个逻辑上的方法表达一个单一函数. 那理解这个单一就很重要了, 单一不是说限制你一个 interface 里只有一个抽象方法, 单一是多个方法的其他方法需要是继承自 Object 的 public 方法, 或者你要想绕过, 就自己实现 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 时, 实现类按照约定也要修改实现, 而 Java8 的 API 对现有接口也添加了很多方法, 比如 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 表达式作为循环体.
来源: http://www.bubuko.com/infodetail-3653600.html