java8学习笔记一FunctionalInterface与Stream

38次阅读

共计 2188 个字符,预计需要花费 6 分钟才能阅读完成。

引言

最近在工作中用到 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 包,为我们提供了诸多的函数式接口,归纳如下:

函数式接口名 参数类型 接口说明
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 ?

流 (Stream) 是 Java API 的新成员, 它允许以声明性的方式处理数据集合(类似于数据库查询语句). 暂且理解为遍历数据集的高级迭代器。

我们可以用一图来归纳 Stream 的通用场景:

正文完
 0