引言
最近在工作中用到java8的Stream流式操作很多,因而对相关概念与实操作简单归纳与总结:
函数式接口
函数式接口是java8新加入特性,为配合lambda表达式而生。lambda表达式与匿名表达式异同可参考 时光隧道 。判断一个接口是否为函数式接口特别简单,只需满足一个条件即可:一个接口有且仅有一个函数(接口默认static及default方法除外)! 即使该接口未被@FunctionalInterface注解标记,但仍为一个函数式接口
我们来看一个示例:
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello the thread.");
}
});
thread.start();
使用lambda表达式创建方式为:
Thread thread=new Thread(()-> System.out.println("hello"));
thread.start();
从示例可以看出,使用lambda表达式配合函数式接口可以大大精简代码,那么函数式接口有什么用呢?
使用lambda表达式调用该函数,将接口方法的实现封装到具体方法,实际也是实现且创建一个接口对象,将方法作为接口实现。更加抽象,只能看到接口方法内部实现。
那么,我们可将常见的使用方式归纳为:
方法引用通过::将方法隶属和方法自身连接起来,如:ClassName :: methodName
1. 静态方法 (args) -> ClassName.staticMethod(args) 转换成 ClassName::staticMethod
2. 实例方法 (args) -> args.instanceMethod() 转换成 ClassName::instanceMethod
3. 外部的实例方法 (args) -> ext.instanceMethod(args) 转换成 ext::instanceMethod(args)
我们来看一个完整的示例:
@FieldDefaults(level = AccessLevel.PRIVATE)
@ToString
public class Kid {
Integer age;
String name;
public Kid(int age, String name) {
this.age = age;
this.name = name;
}
public Integer getAge() {return age;}
public void setAge(Integer age) {this.age = age;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
}
public class MethodReference {
public static void main(String[] args) {
List<Kid> kids = Arrays.asList(
new Kid(10, "奶酪1"),
new Kid(8, "奶酪3"),
new Kid(11, "奶酪2")
);
// 采用lambda表达式排序
kids.sort((Kid a, Kid b) -> compare(a.getAge(), b.getAge()));
kids.forEach(System.out::println);
// 采用方法引用排序
kids.sort(Comparator.comparing(Kid::getName));
kids.forEach(System.out::println);
}
}
输出如下:
Kid(age=8, name=奶酪3),Kid(age=10, name=奶酪1),Kid(age=11, name=奶酪2)
Kid(age=10, name=奶酪1),Kid(age=11, name=奶酪2),Kid(age=8, name=奶酪3)
java8新增的java.util.function包,为我们提供了诸多的函数式接口,归纳如下: