java8新特性学习:函数式接口

时间:2021-09-25 02:31:25

本文概要

  1. 什么是函数式接口?
  2. 如何定义函数式接口?
  3. 常用的函数式接口
  4. 函数式接口语法注意事项
  5. 总结

1. 什么是函数式接口?

函数式接口其实本质上还是一个接口,但是它是一种特殊的接口:SAM类型的接口(Single Abstract Method),在这个接口里面只能有一个抽象方法。

当开发者在编写Lambda表达式时,也会随之被编译成一个函数式接口。Lambda表达式只是语法糖,我们只要理解函数式接口,才能读懂和用好Lambda表达式。

2. 如何定义函数式接口?

@FunctionalInterface
public interface FunctionDemo { void get(String str);
} FunctionDemo fd = str -> System.out.println("Hello " + str);

3. 常用的函数式接口

使用Lambda表达式,一定有函数式接口的支持;但是如果我们每一个Lambda表达式都要自己创建一个接口,

这样很造成很大的不便。为了避免重复造*,java8常用的函数式接口都帮我们定义好,拿来直接使用即可。

如果这些常用的接口不能满足需求时,这时才需要 自定义函数式接口。

下面是我们常用的几类函数式接口:

  • 消费性函数式接口

特点:接受一个或者多个参数,没有返回值

  • 供给型函数式接口

特点:没有参数(无参),提供返回值

  • 函数型函数式接口

特点:接收一个或者多个参数,有返回值

  • 断定性函数式接口

特点:接收一个或者多个参数,返回一个boolean类型

@Test
public void testCoreInter(){
/**
* @name 消费型接口
* @use Consumer<T>
* @param T 传入参数
* @fun 接受一个参数 无返回值
* */
Consumer<String> con=(str)->System.out.println(str);
con.accept("我是消费型接口!"); /**
* @name 供给型接口
* @use Supplier<R>
* @param R 返回值类型
* @fun 无参数 有返回值
* */
Supplier<Date> supp=()-> new Date();
Date date=supp.get();
System.out.println("当前时间:"+date); /**
* @name 函数型接口
* @use Function<T,R>
* @param T 传入参数
* @return R 返回值类型
* @fun 接受一个参数 有返回值
* */
Function<String, String> fun=(str)->"hello,"+str;
String str=fun.apply("张俊强");
System.out.println(str); /**
* @name 断定型接口
* @use Predicate<T>
* @param T 传入参数
* @return Boolean 返回一个Boolean型值
* @fun 接受一个参数 返回Boolean型值
* */
Predicate<Integer> pre=(num)->num>0;
Boolean flag=pre.test(10);
System.out.println(flag);
}

比如方法foreach(),入参为Consumer

default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}

4. 函数式接口语法注意事项

从SAM原则上讲,这个接口中,只能有一个函数需要被实现,但是也可以有如下例外:

  • 默认方法:必须用default修饰,且只能是public,默认也是public。

它也是作为一种向后兼容能力而出现,旧的接口也能用到Lambda表达式中。例如,List或Collection接口是没有forEach方法的声明的。Java 8引入默认方式使得List和Collection接口能够拥有forEach方法的默认实现。实现了这些接口的类也不必再实现相同的功能了。

语法如下所示:

@FunctionalInterface
interface A {
default void test() {
System.out.println("接口A的默认方法");
}
void test1();
}
  • 静态方法

函数式接口中可以有静态方法,一个或者多个静态方法不会影响SAM接口成为函数式接口,并且静态方法可以提供方法实现

@FunctionalInterface
interface TestStaticMethod {
//这是一个抽象方法
void test();
//静态方法,不是抽象方法
static void test1() {
System.out.println("接口里的静态方法!");
}
}

      

      

      

  • 如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
 If an interface declares an abstract method overriding one of the public methods of {@code java.lang.Object},
that also doesnot count toward the interface's abstract method count
since any implementation of the interface will have an implementation from {@code java.lang.Object} or elsewhere. @FunctionalInterface
public interface DemoFunctionalInterface{
void action(); //Object's public methods
String toString();
int hashCode();
boolean equals(Object o);
}
  • 注解@FunctionalInterface不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错

5. 总结

  • 函数式接口只能包含一个抽象方法
  • 函数式接口可以包含Object类中所有public修饰的方法
  • 函数工接口可以包含一个或多个静态方或默认方法

参考文献


tips:本文属于自己学习和实践过程的记录,很多图和文字都粘贴自网上文章,没有注明引用请包涵!如有任何问题请留言或邮件通知,我会及时回复。