java8引入了函数式的编程,在提高代码简洁和可读性的同时也
增强了程序并发执行的能力。这篇文章我们主要关注java8的函数式接口,以及其内置的若干函数式接口。
什么是函数式接口
函数式接口就是只有一个方法的接口,如Runnable、Callable、Comparable都称作函数式接口。java8新加了一个专门用于标识函数式接口的注解@FunctionalInterface
。
有了函数式接口,我们就可以简化原本只能使用匿名函数的代码。
比如使用匿名函数创建一个线程。
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello world!");
}
});
使用java8则只需一行代码。
Thread t1 = new Thread(()->{
System.out.println("hello world!");
});
关于lambda的格式为 ()->{},->为分隔符,左半部分为参数列表(参数在小括号内,无参时小括号为空),右半部分为语句代码(在大括号内部)。
而之所以能够替换,主要由于Runnable
是函数式接口,使用lambda表达式时会自动匹配合适的函数式接口。匹配的规则主要看函数的入参和出参类型、个数是否一致。在Runnable
接口中,其唯一的方法没有入参,出参为void
,与
()->{ System.out.println("hello world!"); }
参数表现一致。
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
内置函数式接口
通过上面示例可以明白,函数式接口最主要看方法中参数的类型和个数,据此,java8提供了一批内置的函数式接口。
接口 | 参数 | 返回类型 | 说明 |
---|---|---|---|
Predicate<T> | T | boolean | 输入某个值,输出bool值,用于对某值进行判定 |
Consumer<T> | T | void | 输入某值,无输出。用于消费某值 |
Function<T,R> | T | R | 输入某类型值,输出另种类型值,用于类型转化等 |
Supplier<T> | None | T | 无输入,输出某值,用于生产某值 |
UnaryOperator<T> | T | T | 输入某类型值,输出同类型值,用于值的同类型转化,如对值进行四则运算等 |
BinaryOperator<T> | (T,T) | T | 输入两个某类型值,输出一个同类型值,用于两值合并等 |
以上函数式接口包含了大部分情况且可直接使用,下面我们就来看一下。
函数式接口
先来看一个例子
@Test
public void filter(){
int[] arr = {1,2,3,4,5,6,7,8,9};
Predicate<Integer> filter = (t)-> t%2==0;
for (int e:arr) {
if(filter.test(e)){
System.out.println(e+"是偶数");
}
}
}
Predicate
即是上面介绍的内置接口,用于对某值进行判定。这里传入了判定是否为偶数的行为,对一个数组进行判断。结果就不贴了。
java8封装了对数组集合的操作,并引入了Stream
(流)的概念,通过使用函数式接口使得对集合操作更加便捷。
@Test
public void forEach(){
List<Integer> list = Arrays.asList(1,2,3,4,5);
list.forEach(e->System.out.print(e+" "));
}
输出: 1 2 3 4 5
其中的forEach
使用的就是内置的函数接口Consumer
default void forEach(Consumer<? super T> action)
在上面的例子中,我们传入了遍历每个元素的行为代码。
还可以进行链式操作,对数组进行过滤、转化、遍历等多种操作。具体有关Stream
可参考java8 Stream用法详解。总之,其内置的几个函数接口是函数编程的基础,对理解lambda
表达式和函数编程都有关键作用。
———全文完————————