函数式接口详细定义
package java.lang;import java.lang.annotation.*;/*** An informative annotation type used to indicate that an interface* type declaration is intended to be a functional interface as* defined by the Java Language Specification.** Conceptually, a functional interface has exactly one abstract* method. Since { @linkplain java.lang.reflect.Method#isDefault()* default methods} have an implementation, they are not abstract. If* an interface declares an abstract method overriding one of the* public methods of { @code java.lang.Object}, that also does* not 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.**Note that instances of functional interfaces can be created with* lambda expressions, method references, or constructor references.**
If a type is annotated with this annotation type, compilers are* required to generate an error message unless:**
- *
- The type is an interface type and not an annotation type, enum, or class.*
- The annotated type satisfies the requirements of a functional interface.*
However, the compiler will treat any interface meeting the* definition of a functional interface as a functional interface* regardless of whether or not a {
@code FunctionalInterface}* annotation is present on the interface declaration.** @jls 4.3.2. The Class Object* @jls 9.8 Functional Interfaces* @jls 9.4.3 Interface Method Body* @since 1.8*/@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface FunctionalInterface {}关键概念
函数式接口只有一个抽象方法 由于default方法有一个实现,所以他们不是抽象的. 如果一个接口定义了一个抽象方法,而他恰好覆盖了Object的public方法,仍旧不算做接口的抽象方法, 因为它终将会在某处得到一个实现.(如果不是public的那么计数) 也即是只有一个抽象方法默认不算,Object的public也不算 |
函数式接口的实例可以通过 lambda表达式 方法引用 或者构造方法引用进行表示 |
类型必须是接口,而不能是其他的比如class 而且需要符合函数式接口的定义要求 否则使用注解时编译器报错 |
不管他们是否有使用注解FunctionalInterface 进行注解, 编译器将会把任何满足函数式接口定义的接口当做一个函数式接口 也就是说不加也行,但是显然不加的话,就没有限制约束,后续可能增加了其他方法导致出错 |
常用函数式接口
接口 抽象方法
|
java.util.function.Predicate<T> 断言 也就是条件测试器 接收条件,进行测试 接口定义了一个名叫test的抽象方法,它接受泛型T对象,并返回一个boolean。 test (条件测试) , and-or- negate(与或非) 方法 |
java.util.function.Consumer<T> 消费者 消费数据 接收参数,返回void 数据被消费了 定义了一个名叫accept的抽象方法,它接受泛型T的对象,没有返回(void) 你如果需要访问类型T的对象,并对其执行某些操作,就可以使用这个接口 |
java.util.function.Function<T, R> 函数 有输入有输出 数据转换功能 接口定义了一个叫作apply的方法,它接受一个泛型T的对象,并返回一个泛型R的对象。 |
java.util.function.Supplier<T>提供者 不需要输入,产出T 提供数据无参构造方法 提供T类型对象 |
接口中的compose, andThen, and, or, negate 用来组合函数接口而得到更强大的函数接口 四大接口为基础接口,其他的函数接口都是通过这四个扩展而来的 此处的扩展是指概念的展开 不是平常说的继承或者实现,当然实现上可能是通过继承比如UnaryOperator |
扩展方式:
为什么要有基本类型扩展
- 如果参数是基本类型,则不加前缀只需类型名即可
- 如果方法返回类型为基本类型,则在基本类型前再加上一个 To
加了类型前缀[Int|Double|Long] 表示参数是基本类型, 如果在此基础上又加上了To 表示返回类型是基本类型 |
函数式接口的实例
Lambda表达式
- 匿名——我们说匿名,是因为它不像普通的方法那样有一个明确的名称:写得少而想得多!
- 函数——我们说它是函数,是因为Lambda函数不像方法那样属于某个特定的类。但和方法一样,Lambda有参数列表、函数主体、返回类型,还可能有可以抛出的异常列表。
- 传递——Lambda表达式可以作为参数传递给方法或存储在变量中。
- 简洁——无需像匿名类那样写很多模板代码。
(parameters) -> expression |
(parameters) -> { statements; } |
- 参数列表
- 箭头 ( -> 把参数列表与Lambda主体分隔开)
- Lambda主体 (表达式或者语句)
() -> {System.out.print("Hello");System.out.println(" World");};
方法引用
构造函数引用
class A {private String s1="a";private String s2="b";private String s3="c";A(){}A(String s1){this.s1=s1;}A(String s1,String s2){this.s1=s1;this.s2=s2;}A(String s1,String s2,String s3){this.s1=s1;this.s2=s2;this.s3=s3;}@Overridepublic String toString() {final StringBuilder sb = new StringBuilder("A{");sb.append("s1='").append(s1).append('\'');sb.append(", s2='").append(s2).append('\'');sb.append(", s3='").append(s3).append('\'');sb.append('}');return sb.toString();}}
类型检查与类型推断
类型检查
函数式接口 变量名 = Lambda-匿名函数/方法引用/构造方法引用; |
List<Integer> listNum = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
List filteredNum = listNum.stream().filter(i -> i.compareTo(5) < 0).collect(Collectors.toList());
System.out.println(filteredNum);
1. 通过形参类型或者变量类型 找到函数接口进而找到抽象方法的声明 2. 然后在与参数值进行比对查看是否匹配 |
如果不同的函数接口,具有相互兼容的抽象方法签名 那么一个Lambda表达式显然可以匹配多个函数接口 |
特殊的void兼容规则 如果一个Lambda的主体是一个语句表达式, 它就和一个返回void的函数描述符兼容(当然需要参数列表也兼容)。 就是说 如果主体是一个语句,不管做什么或者调用方法返回其他的类型,他都可以兼容void |
List<String> list= new ArrayList<>();
// Predicate返回了一个boolean
Predicate<String> p = s -> list.add(s);
// Consumer返回了一个void
Consumer<String> b = s -> list.add(s);
类型推断
List<String> list = new ArrayList<String>(); |
List<String> list = new ArrayList<>(); |
.filter((Integer i) -> { return i.compareTo(5) < 0;}).collect(Collectors.toList());
.filter((Integer i) ->i.compareTo(5) < 0).collect(Collectors.toList());
.filter(i ->i.compareTo(5) < 0).collect(Collectors.toList());