先来看看传统的建立线程是怎么写的java
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t1");
}
});
t1.start();
复制代码
再来看看使用了函数式接口是怎么写的bash
Thread t2 = new Thread(() -> System.out.println("t2"));
t2.start();
复制代码
Runnable接口直接能够使用Lambda表达式来编写,这是由于Runnable接口是一个函数式接口,来看看Runnable的源码。微信
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
复制代码
发现该接口加上了函数式接口的定义注解:@FunctionalInterface
,代表该接口是一个函数式接口。多线程
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {
}
复制代码
在JDK8中,除了Runnbale接口,还有像Comparator、Callable等接口都加上了该注解定义为函数式接口。app
JDK8提供了几个内置的函数式接口,用在了许多API的地方,均可以拿来用,能够知足大部分应用。ide
//Consumer<T> - T做为输入,执行某种动做但没有返回值
Consumer<String> con = (x) -> {
System.out.println(x);
};
con.accept("hello world");
//Supplier<T> - 没有任何输入,返回T
Supplier<String> supp = () -> {
return "Supplier";
};
System.out.println(supp.get());
//Predicate<T> -T做为输入,返回的boolean值做为输出
Predicate<String> pre = (x) -> {
System.out.print(x);
return x.startsWith("op");
};
System.out.println(": " + pre.test("op, hello World"));
// Function<T, R> -T做为输入,返回的R做为输出
Function<String, String> function = (x) -> {
System.out.print(x + ": ");
return "Function";
};
System.out.println(function.apply("hello world"));
//BinaryOperator<T> -两个T做为输入,返回一个T做为输出,对于“reduce”操做颇有用
BinaryOperator<String> bina = (x, y) -> {
System.out.print(x + " " + y);
return "BinaryOperator";
};
System.out.println(" " + bina.apply("hello ", "world"));
复制代码
@FunctionalInterface
public interface CalcInterface<N, V> {
V operation(N n1, N n2);
}
复制代码
这里只有一个抽象方法,@FunctionalInterface注解能够不用写,至于为何能够往下看。函数
public static class NumberOperation<N extends Number, V extends Number> {
private N n1;
private N n2;
public NumberOperation(N n1, N n2) {
this.n1 = n1;
this.n2 = n2;
}
public V calc(CalcInterface<N, V> ci) {
V v = ci.operation(n1, n2);
return v;
}
}
复制代码
private static void testOperationFnInterface() {
NumberOperation<Integer, Integer> np = new NumberOperation(13, 10);
CalcInterface<Integer, Integer> addOper1 = (n1, n2) -> {
return n1 + n2;
};
CalcInterface<Integer, Integer> multiOper1 = (n1, n2) -> {
return n1 * n2;
};
System.out.println(np.calc1(addOper1));
System.out.println(np.calc1(multiOper1));
// 上面的能够简写为
System.out.println(np.calc1((n1, n2) -> n1 + n2));
System.out.println(np.calc1((n1, n2) -> n1 * n2));
}
复制代码
最后输出:测试
23
130
23
130
复制代码
一、@FunctionalInterface标识为一个函数式接口只能用在只有一个抽象方法的接口上。ui
二、接口中的静态方法、默认方法、覆盖了Object类的方法都不算抽象方法。this
三、@FunctionalInterface注解不是必须的,若是该接口只有一个抽象方法能够不写,它默认就符合函数式接口,但建议都写上该注解,编译器会检查该接口是否符合函数式接口的规范。
正确的函数式接口。
@FunctionalInterface
public interface CalcInterface<N, V> {
V operation(N n1, N n2);
}
复制代码
加了几个符合函数式的方法也没事,编译器也不会报错。
@FunctionalInterface
public interface CalcInterface<N, V> {
V operation(N n1, N n2);
public boolean equals(Object object);
public default void defaultMethod() {
}
public static void staticMethod() {
}
}
复制代码
这个没用@FunctionalInterface函数式接口,有两个抽象方法,不能用于Lambda表达式。
public interface CalcInterface<N, V> {
V operation(N n1, N n2);
V operation2(N n1, N n2);
}
复制代码
这个有两个抽象方法的用@FunctionalInterface注解的函数式接口编译会报错。
@FunctionalInterface
public interface CalcInterface<N, V> {
V operation(N n1, N n2);
V operation2(N n1, N n2);
}
复制代码
这个没有一个抽象方法,编译报错。
public interface CalcInterface<N, V> {
}
复制代码
扫码关注Java技术栈微信公众号,在后台回复:java,获取栈长整理的一份最新 Java 技术教程,内容包括 Java 基础、多线程、JVM、新特性等更多实战干货。