Java 8 Guide E2

本篇接着上篇来, 继续学习java8新特性
Java 8 简明教程

自定义一个函数式接口

代码展示

/**
 * @author imyzt
 * @date 2019/1/17 18:23
 * @description 自定义函数式接口
 */
public class FunctionInterfaceDemo {
    public static void main(String[] args) {

        Person<Boolean> person = Objects::nonNull;
        Boolean aaa = person.say("aaa");
        System.out.println("传入的信息是否不为空: " + aaa);

        Person<String> person1 = (msg) -> "Hello "+msg;
        String say = person1.say("World");
        System.out.println(say);
    }
}

@FunctionalInterface
interface Person<T extends Object> {
    T say(String msg);
}

讲解

码中定义了一个接口 Person, 接口上使用了 @FunctionalInterface 注解, 接口泛型Object是一个约束, 在这里只是演示. 实际场景中可以写需要被约束的父类.
使 用的时候, 实例 person 的泛型是 Boolean 布尔类型, 所以在表达式的右边, 也就是具体的实现上我调用了Objects的nonNull方法. :: 表达式可以直接引用对象的方法.
person1 的泛型是 String 字符串类型, 所以在表达式的右边可以定义对 say(String msg) 中msg的操作, 然后调用say()方法时就会执行上述操作.

结果输出

传入的信息是否不为空: true
Hello World

内置函数式接口

Java8内置了很多函数式接口便于我们使用;
当然,我们也可以自定义函数式接口通过**@FunctionalInterface**注解声明.
java.util.function下的接口最多支持到二元运算。有了这些接口,我们就可以省去创建接口的功夫,而直接使用lambda了。
Nilary 零元,Unary 一元,Binary 二元,Ternary 三元,Quaternary 四元。对于一个算子来说,一个参数,就是一元运算;2个参数就是二元运算。

Predicate

Predicate是一个布尔类型的函数,该函数只有一个输入参数。
Predicate接口包含了多种默认方法,用于处理复杂的逻辑动词(and, or,negate)
摘抄自 http://blog.didispace.com/books/java8-tutorial/ch1.html

Predicate<String> predicate = (a) -> a.startsWith("a");
Predicate<String> predicate2 = Objects::nonNull;

boolean test = predicate.negate().and(predicate2).test("abc");
System.out.println(test);

Consumer

Consumer 消费target type。参数 T,无返回值(void)。
Consumer可以理解为一个消费者, 因为他没有返回值, 只接收一个参数, 按照重写的方法执行完成后即完成操作.

Consumer<String> consumer = System.out::println;
consumer.accept("hello world");

Function

Function 对target type做转换。参数T,返回R。

Predicate<String> predicate = s -> null != s && s.startsWith(v26);

Function<String, String> function = s -> predicate.test(pageInfo) ?
sdkHttpKit.ipPort().append(s).toString() :
sdkHttpKit.uri().append("face/meta/").append(URLUtil.encode(meta)).toString();

String url = function.apply(pageInfo);

Supplier

Supplier 供应target,可以理解为target的factory。无参,返回T。
Supplier 可以理解为工厂类, 通过下面的演示可以看出它能够创建对象.不过我看了别人的博客, 理解为这个方法可以将耗时的操作放进去. 在没有调用get()方法之前, 是不会执行的.可以降低系统运行时间.
Main.java

Supplier<People> supplier = People::new;
// 在需要的时候可以调用get()方法获得一个新的People对象.
People people = supplier.get();
people.hello();

输出: hello

People.java

class People {
    void hello() {
        System.out.println("hello");
    }
}

UnaryOperator

UnaryOperator 一元运算。继承Function接口。参数T,返回T。
UnaryOperator 可以理解为对参数T进行处理.

UnaryOperator<String> unaryOperator = s -> s + "___";
System.out.println(unaryOperator.apply("hello"));

输出: hello___

BinaryOperator

BinaryOperator 二元运算。参数 T,返回R。
BinaryOperator为UnaryOperator的二元运算, 它接收两个T参数, 返回的也是T参数, 可以理解对两个参数的条件操作

BiPredicate<String, String> biPredicate =
    (s1, s2) -> s1.startsWith("s1") && s2.endsWith("s2");

BinaryOperator<String> binaryOperator =
    // 当条件满足时, 执行三目运算的第一个操作. 否则第二个操作执行.
    (s1, s2) -> biPredicate.test(s1, s2) ?
    s2 + "_" + s1 : s1 + "_" + s2;
        
System.out.println(binaryOperator.apply("s1" , "s2"));

输出: s2_s1

Comparator

这个可以用来做比较. 在上一篇已经有使用过了. 此处添加一点演示代码

Supplier<People> supplier = People::new;

People people1 = supplier.get();
people1.setPeopleId(10);
People people2 = supplier.get();
people2.setPeopleId(100);

Comparator<People> comparator1 = Comparator.comparing(People::getPeopleId);
System.out.println(comparator1.compare(people2, people1));

Comparator<People> comparator2 = (p1, p2) -> p1.getPeopleId() > p2.getPeopleId() ? 1 : 0;
System.out.println(comparator2.compare(people1, people2));

第一个输出: 1  
第二个输出: 0

Binary

Consumer、Function、Predicate分别还对应了Bi的函数式接口。
它们的操作与对应的一元运算也是大同小异, 只是参数多了一个. 就不细讲了
对应的也就是二元运算函数。分别是

  • BiConsumer<T, U> 接收T对象和U对象,不返回值
  • BiPredicate<T, U> 接收T对象和U对象,返回boolean
  • BiFunction<T, U, R> 接收T对象和U对象,返回R对象

总结

接口一大堆, 我所理解的

  • Consumer, BiConsumer: 消费

  • Predicate, BiPredicate: 条件判断

  • Function, BiFunction, UnaryOperator, BinaryOperator: 参数处理

  • Supplier: 工厂