Java 没有委托的概念; 相反,如果需要一个指向函数的指针,可以创建内联匿名类(或 Java 8 的 lambda 表达式),它们是为此建议设计的某些接口的实现(也称为 Java 8 的功能接口)。 然而,随着 Java 的发展,越来越多的此类接口被添加进来。 虽然它们看起来非常相似且令人困惑,但它们中的每一个都有一个独特的特征,使其与众不同。 可以将它们中的许多映射到 .NET 中的相同类型。 下表列出了一些著名的接口,但还有更多。 例如,为了支持带有两个参数的函数,Java 有另一个接口称为 BiFunction,如果您需要更多参数,则必须创建自己的接口。 请记住,如果唯一的区别是类型参数的数量,Java(最高版本 10)不支持相同的类名。 (在 .NET 中有各种 Func 和 Action 类型,最多有 16 个类型参数。)
Supplier () -> x
Consumer x -> ()
Callable () -> x throws ex
Runnable () -> ()
Function x -> y
Runnable
Since Java’s early days, multithreading has been a major aspect of the
language. Runnable is the core interface provided for representing
multithreaded tasks, and Java 1.5 provided Callable as an improved
version of Runnable.
Runnable 接口是一个函数式接口,有一个不接受任何参数或返回任何值的 run() 方法。
这适用于我们不寻找线程执行结果的情况,例如传入事件日志记录:
public interface Runnable {
public void run();
}
public class EventLoggingTask implements Runnable{
private Logger logger
= LoggerFactory.getLogger(EventLoggingTask.class);
@Override
public void run() {
logger.info("Message");
}
}
在此示例中,线程将仅从队列中读取消息并将其记录在日志文件中。任务没有返回任何值。 我们可以使用 ExecutorService 启动任务:
public void executeTask() {
executorService = Executors.newSingleThreadExecutor();
Future future = executorService.submit(new EventLoggingTask());
executorService.shutdown();
}
Callable
Callable 接口是一个通用接口,包含一个返回通用值 V 的 call() 方法:
public interface Callable<V> {
V call() throws Exception;
}
public class FactorialTask implements Callable<Integer> {
int number;
// standard constructors
public Integer call() throws InvalidParamaterException {
int fact = 1;
// ...
for(int count = number; count > 1; count--) {
fact = fact * count;
}
return fact;
}
}
@Test
public void whenTaskSubmitted_ThenFutureResultObtained(){
FactorialTask task = new FactorialTask(5);
Future<Integer> future = executorService.submit(task);
assertEquals(120, future.get().intValue());
}
Consumer
从字面意思上我们就可以看得出,consumer接口就是一个消费型的接口,通过传入参数,然后输出值
我们下面就先看一个例子
@Test
public void test_Consumer() {
//① 使用consumer接口实现方法
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
Stream<String> stream = Stream.of("aaa", "bbb", "ddd", "ccc", "fff");
stream.forEach(consumer);
System.out.println("********************");
//② 使用lambda表达式,forEach方法需要的就是一个Consumer接口
stream = Stream.of("aaa", "bbb", "ddd", "ccc", "fff");
Consumer<String> consumer1 = (s) -> System.out.println(s);//lambda表达式返回的就是一个Consumer接口
stream.forEach(consumer1);
//更直接的方式
//stream.forEach((s) -> System.out.println(s));
System.out.println("********************");
//③ 使用方法引用,方法引用也是一个consumer
stream = Stream.of("aaa", "bbb", "ddd", "ccc", "fff");
Consumer consumer2 = System.out::println;
stream.forEach(consumer);
//更直接的方式
//stream.forEach(System.out::println);
}
lambda 表达式作为 consumer
Consumer<String> consumer1 = (s) -> System.out.println(s);
方法引用作为 consumer
Consumer consumer2 = System.out::println;
Supplier
Supplier 接口是一个供给型的接口,其实,说白了就是一个容器,可以用来存储数据,然后可以供其他方法使用的这么一个接口。
@Test
public void test_Supplier() {
//① 使用Supplier接口实现方法,只有一个get方法,无参数,返回一个值
Supplier<Integer> supplier = new Supplier<Integer>() {
@Override
public Integer get() {
//返回一个随机值
return new Random().nextInt();
}
};
System.out.println(supplier.get());
System.out.println("********************");
//② 使用lambda表达式,
supplier = () -> new Random().nextInt();
System.out.println(supplier.get());
System.out.println("********************");
//③ 使用方法引用
Supplier<Double> supplier2 = Math::random;
System.out.println(supplier2.get());
}
看一下这段代码,我们通过创建一个 Supplier 对象,实现了一个 get 方法,这个方法无参数,返回一个值;所以,每次使用这个接口的时候都会返回一个值,并且保存在这个接口中,所以说是一个容器。
Supplier<Integer> supplier = new Supplier<Integer>() {
@Override
public Integer get() {
//返回一个随机值
return new Random().nextInt();
}
};
Supplier<Double> supplier2 = Math::random;
System.out.println(supplier2.get());