Java8之函数接口
函数接口
Java8新特性提供了函数式接口,用于更好的支持函数式编程。
定义
所谓函数式接口就是只有一个抽象方法的接口。Java8中可以通过注解(@FunctionalInterface)来限定它(即便不加注解,只有一个抽象方法默认也是函数式接口)。
比如:
public interface MyInterface {
void myFunction();
}
加上注解@FunctionalInterface后,当超出一个抽象方法时,直接编译报错。
@FunctionalInterface
public interface MyInterface {
void myFunction();
}
默认方法
Java8运行接口有默认方法,用default 关键字修饰即可,当然可以有多个默认方法。注意,默认方法只能是public,且默认是public。
@FunctionalInterface
public interface MyInterface {
void myFunction();
default void defaultFunction1() {
System.out.println("Interface : default function1");
}
default void defaultFunction2() {
System.out.println("Interface : default function2");
}
}
静态方法
Java8支持接口有静态方法,另外调用时,使用接口名调用静态方法。注意,默认方法只能是public,且默认是public。@FunctionalInterface
public interface MyInterface {
void myFunction();
static void staticFunction() {
System.out.println("Interface : staticFunction");
}
}
与类的静态方法调用方式一样:MyInterface.staticFunction();
使用
虽然函数式接口提供了这些功能,不过使用时需要更加小心。比如多个接口的继承和实现问题。下面用一个例子说明下,先看类图:
这里有三个接口,SubInterface extends 另外两个接口。下边是各个类的代码:
InterfaceA 拥有两个默认方法,一个静态方法和一个抽象方法。
@FunctionalInterface
public interface InterfaceA {
default void defaultFunction() {
System.out.println("InterfaceA : defaultFunction");
}
default void defaultFunction2() {
System.out.println("InterfaceA : defaultFunction 2");
}
static void staticFunction() {
System.out.println("InterfaceA : staticFunction");
}
void functionNormal();
}
函数接口InterfaceB类似,只有一个默认方法,不过该默认方法与InterfaceA的一个方法签名一样。
@FunctionalInterface
public interface InterfaceB {
default void defaultFunction() {
System.out.println("InterfaceB : defaultFunction");
}
static void staticFunction() {
System.out.println("InterfaceB : staticFunction");
}
void functionNormal();
}
而函数接口SubInterface 同时继承了上边两个接口。
@FunctionalInterface
public interface SubInterface extends InterfaceA, InterfaceB{
default void defaultFunction() {// 两个默认方法一样,必须重写。
this.defaultFunction2();// 默认方法 可以被继承
System.out.println("SubInterface : defaultFunction");
}
static void staticFunction() {
InterfaceA.staticFunction();
InterfaceB.staticFunction();
System.out.println("SubInterface : staticFunction");
}
void functionNormal();
}
注意:
1.默认方法可以被继承,因此SubInterface 拥有 InterfaceA 的默认方法 defaultFunction2()。
2.因为多继承问题,两个默认方法重名,此时子接口必须重写该冲突默认方法,否则编译报错。
现在类MyImplClass 实现了上边的子接口:
public class MyImplClass implements SubInterface {
@Override
public void defaultFunction() {
System.out.println("default Function can be implemented by class.");
}
@Override
public void functionNormal() {
System.out.println("MyImplClass : functionNormal");
}
}
发现:默认方法可以被类重写。
测试下我们的类:
public static void main(String[] args) {
SubInterface m = new MyImplClass();
SubInterface.staticFunction();
m.functionNormal();
m.defaultFunction();
System.out.println("----------------------");
SubInterface m2 = new SubInterface(){
@Override
public void functionNormal() {
System.out.println("InterfaceB : functionNormal self implement.");
}
};
m2.functionNormal();
m2.defaultFunction();
}
输出如下:
InterfaceA : staticFunction
InterfaceB : staticFunction
SubInterface : staticFunction
MyImplClass : functionNormal
default Function can be implemented by class.
----------------------
InterfaceB : functionNormal self implement.
InterfaceA : defaultFunction 2
SubInterface : defaultFunction
四大函数接口
Java8页内置了四个比较重要的函数式接口供我们使用:Predicate。简单举个例子:
Predicate
Predicate接口用于断言,也叫谓语接口,简单的判断“是”与“不是”:收一个参数,返回一个boolean值。因此多用于判断和过滤。
// predicate<T> 断言型接口:
public void process() {
List<Integer> list = Arrays.asList(21, 34, 44, 55, 66);
list = filterOutElement(list, v -> v > 40);
list.forEach(System.out::println);
}
// 过滤出满足条件的元素
public List<Integer> filterOutElement(List<Integer> list, Predicate<Integer> predicate) {
List<Integer> resultList = new ArrayList<>();
for (Integer temp : list) {
if (predicate.test(temp))
resultList.add(temp);
}
return resultList;
}
Function
即函数型接口。函数式编程中函数是可以作为参数的。该接口的作用即是如此。这样函数就可以被传递与复用。说白了就是数学中的复合函数:f(g(x))。 g(x) 作为f(y)的参数。 //Function<T,R>函数型接口
public void formatUpper() {
String str = formatHandler("My text input", s -> s.toUpperCase());
System.out.println(str);
}
// 根据传入的函数表达式进行处理
public String formatHandler(String str, Function<String, String> fun) {
return fun.apply(str);
}
这里 formatHandler 就是 f(y),Lambda 表达式 s -> s.toUpperCase() 就是 g(x) .Supplier
从名字就可以知道,是一个提供者。拥有 get() 方法,用它可以产生或者获取我们要求的数据。
// Supplier<T>供给型接口:
public void getRandom() {
List<Integer> list = getIntegerList(10, () -> (int) (Math.random() * 100));
list.forEach(System.out::println);
}
// 提*生指定个数的Integer 生成器
public List<Integer> getIntegerList(int size, Supplier<Integer> sup) {
List<Integer> resultList = new ArrayList<>();
for (int i = 0; i < size; i++) {
resultList.add(sup.get());
}
return resultList;
}
Consumer
跟上边相反,该函数式接口用于消费数据。比如对于获取的数据,做下一步的处理。
//Consumer<T> 消费型接口
public void consumerGivenString() {
List<String> result = Arrays.asList("Hust", "ZW", "Kaka");
outputHandler(result, strs -> strs.forEach(str -> System.out.println(str)));
}
public void outputHandler(List<String> strs, Consumer<List<String>> con) {
con.accept(strs);
}