最近在工做中用到java8的Stream流式操做不少,于是对相关概念与实操做简单概括与总结:java
函数式接口是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表达式建立方式为:
ide
Thread thread=new Thread(()-> System.out.println("hello")); thread.start();
从示例能够看出,使用lambda表达式配合函数式接口能够大大精简代码,那么函数式接口有什么用呢?
函数
使用lambda表达式调用该函数,将接口方法的实现封装到具体方法,实际也是实现且建立一个接口对象,将方法做为接口实现。更加抽象,只能看到接口方法内部实现。
那么,咱们可将常见的使用方式概括为:
post
方法引用经过::将方法隶属和方法自身链接起来,如:ClassName :: methodName
1. 静态方法 (args) -> ClassName.staticMethod(args) 转换成 ClassName::staticMethod
2. 实例方法 (args) -> args.instanceMethod() 转换成 ClassName::instanceMethod
3. 外部的实例方法 (args) -> ext.instanceMethod(args) 转换成 ext::instanceMethod(args)
咱们来看一个完整的示例:
this
@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); } }
输出以下:
spa
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包,为咱们提供了诸多的函数式接口,概括以下:
code
函数式接口名 | 参数类型 | 接口说明 |
---|---|---|
Supplier | Supplier< T > | 提供T对象(例如工厂),不接收值 |
Consumer | Consumer< T > | 接收T对象,不返回值 |
Predicate | Predicate< T > | 接收T对象并返回boolean |
Function | Function< T, R > | 接收T对象,返回R对象 |
UnaryOperator | UnaryOperator< T > | 接收T对象,返回T对象 |
BiConsumer | BiConsumer<T, U> | 接收T对象和U对象,不返回值 |
BiPredicate | BiPredicate<T, U> | 接收T对象和U对象,返回boolean |
BiFunction | BiFunction<T, U, R> | 接收T对象和U对象,返回R对象 |
BinaryOperator | BinaryOperator< T > | 接收两个T对象,返回T对象 |
函数式接口须配合Stream才能发挥其最大的用处,接下来咱们对Steam接口方法常见使用方式进行举例。
何为Stream ?对象
流(Stream)是Java API的新成员,它容许以声明性的方式处理数据集合(相似于数据库查询语句).暂且理解为遍历数据集的高级迭代器。
咱们能够用一图来概括Stream的通用场景:blog