Java 8新特性(3) 内置函数式接口

JDK 1.8 API 中包含了很多内置的函数式接口。有些是在以前版本的 Java 中大家耳熟能详的,例如 Comparator 接口,或者 Runnable 接口。对这些现成的接口进行实现,可以通过 @FunctionalInterface 标注来启用 Lambda 功能支持。

文档查看:https://docs.oracle.com/javase/8/docs/api/

Predicate

Predicate 是一个布尔类型的函数,该函数只有一个输入参数。Predicate 接口包含了多种默认方法,用于处理复杂的逻辑动词(and, or,negate)

源码

package java.util.function;

import java.util.Objects;

@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);

    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }

实例

Predicate<String> predicate = (s) -> s.length() > 0;

predicate.test("foo");  // true
predicate.negate().test("foo");  // false

Predicate<Boolean> nonNull = Objects::nonNull;
Predicate<Boolean> isNull = Objects::isNull;

Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isNotEmpty = isEmpty.negate();
Predicate<String> isEqual = Predicate.isEqual("Str");

nonNull.test(null)  // false

Function

Function 接口接收一个参数,并返回单一的结果。默认方法可以将多个函数串在一起(compse, andThen)

源码

package java.util.function;

import java.util.Objects;

/**
 * @param <T> 函数的输入类型
 * @param <R> 函数结果的类型
 */
@FunctionalInterface
public interface Function<T, R> {

    /**
     * 将此函数应用于给定的参数。
     */
    R apply(T t);

    /**
     * 返回一个复合函数,该函数首先计算{@code before}函数,再计算当前函数,顺序同 andThen 方法相反。
     *
     * @param <V> {@code before}函数的输出类型,也是复合函数的输入类型
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    /**
     * 返回一个复合函数,该函数首先计算当前函数,然后将{@code after}函数应用于结果。
     *
     * @param <V> {@code after}函数的输出类型,也是复合函数的输出类型
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    /**
     * Returns a function that always returns its input argument.
     *
     * @param <T> the type of the input and output objects to the function
     * @return a function that always returns its input argument
     */
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

andThen 方法实例

Function<String, Integer> toInteger = Integer::valueOf;
Function<String, String> backToString = toInteger.andThen(String::valueOf);  // 先计算 toInteger 函数
System.out.println(backToString.apply("123") + 1);    // 1231

Function<String, String> toString = String::valueOf;
Function<String, Integer> backToInt = toString.andThen(toInteger);    // 先计算 toString 函数
System.out.println(backToInt.apply("123") + 1);    // 124

compose 方法实例

Function<String, Integer> toInteger = Integer::valueOf;
Function<String, Integer> backToString = toInteger.compose(String::valueOf);  // 先计算 String::valueOf 函数
System.out.println(backToString.apply("123") + 1);    // 124

Function<Integer, String> toString = String::valueOf;
Function<String, String> backToInt = toString.compose(toInteger);  // 先计算 toInteger 函数
System.out.println(backToInt.apply("123") + 1);    // 1231

identity 方法实例

返回一个始终返回其输入参数的函数。

// 源码
static <T> Function<T, T> identity() {
    return t -> t;
}

// 例子
Function.identity().apply(4);  // 4

Function.identity()t->t 区别:

  • t->t:可读性好
  • Function.identity():可节省一些内存,有些情况下不可用

https://stackoverflow.com/questions/28032827/java-8-lambdas-function-identity-or-t-t

Supplier

Supplier 接口产生一个给定类型的结果。与 Function 不同的是,Supplier 没有输入参数。

源码

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     */
    T get();
}

实例

Supplier<Person> personSupplier = Person::new;
personSupplier.get();   // new Person

Consumer

Consumer 代表了在一个输入参数上需要进行的操作。

源码

@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);

    /**
     * 同 Function 类中的 andThen 方法调用顺序
    */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

实例

Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName);
Consumer<Person> greeter2 = greeter.andThen((p) -> System.out.println("Hello, " + p.lastName));
// greeter.accept(new Person("Luke", "Skywalker"));
greeter2.accept(new Person("Luke", "Skywalker"));
/** output:
Hello, Luke
Hello, Skywalker
/

Comparator

java.util.Comparator 接口在早期的Java版本中非常著名。Java 8 为这个接口添加了很多默认方法。

Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName);

Person p1 = new Person("John", "Doe");
Person p2 = new Person("Alice", "Wonderland");

comparator.compare(p1, p2);             // > 0
comparator.reversed().compare(p1, p2);  // < 0  // reversed() 返回一个比较器,相反顺序。

reverseOrder(),返回与自然顺序相反的比较器。

naturalOrder(),返回按自然顺序比较对象的比较器。

comparing

静态方法,两种重载方法

Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName);

Person p1 = new Person("John", "Doe");
Person p2 = new Person("Alice", "Wonderland");

Comparator<Person> c = Comparator.comparing(Person::getFirstName, String.CASE_INSENSITIVE_ORDER);
System.out.println(c.compare(p1, p2));  // > 0

Comparator<Person> c2 = Comparator.comparing(Person::getFirstName);
System.out.println(c2.compare(p1, p2));  // > 0

另外还有 comparingInt,comparingLong,comparingDouble 方法。

thenComparing

thenComparing 有三种重载方法

// 1.
default Comparator<T> thenComparing(Comparator<? super T> other) {
    Objects.requireNonNull(other);
    return (Comparator<T> & Serializable) (c1, c2) -> {
        int res = compare(c1, c2);
        return (res != 0) ? res : other.compare(c1, c2);
    };
}
// 实例1:要根据长度进行排序,然后对不区分大小写的自然顺序进行排序,可以使用以下代码组合比较器,
Comparator<String> cmp = Comparator.comparingInt(String::length).thenComparing(String.CASE_INSENSITIVE_ORDER);
System.out.println(cmp.compare("abc", "ccc"));  // < 0

// 实例2:firstName 相同,按 lastName 排序
p1 = new Person("Alice", "Doe");
p2 = new Person("Alice", "Wonderland");

Comparator<Person> comparator2 = (p1, p2) -> p1.lastName.compareTo(p2.lastName);
Comparator<Person> cmp3 = comparator.thenComparing(comparator2);
cmp3.compare(p1, p2)  // < 0

// 2.
default <U> Comparator<T> thenComparing(
        Function<? super T, ? extends U> keyExtractor, Comparator<? super U> keyComparator) {
    return thenComparing(comparing(keyExtractor, keyComparator));
}
// 实例:firstName 相同,按 lastName 排序
Comparator<Person> cmp4 = comparator.thenComparing(Person::getLastName, String.CASE_INSENSITIVE_ORDER);
System.out.println(cmp4.compare(p1, p2));  // < 0

// 3.
default <U extends Comparable<? super U>> Comparator<T> thenComparing(
        Function<? super T, ? extends U> keyExtractor) {
    return thenComparing(comparing(keyExtractor));
}

// 实例:自然顺序相同,按长度排序
Comparator<String> cmp2 = String.CASE_INSENSITIVE_ORDER.thenComparing(String::length);
System.out.println(cmp2.compare("abc", "acc"));  // < 0

另外还有 thenComparingInt,thenComparingLong,thenComparingDouble 方法。

nullsFirst,nullsLast

返回一个空值友好的比较器,当两者都是 null 时相等,如果两者都为非 null,则使用指定的 Comparator 来确定顺序。如果指定的比较器是 null ,则所有非空值都相等。

nullsFirst,它将 null 视为小于非 null。

nullsLast,它将 null 视为大于非 null。

public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
    return new Comparators.NullComparator<>(true, comparator);
}

public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
    return new Comparators.NullComparator<>(false, comparator);
}

Optional

Optional 不是一个函数式接口,而是一个精巧的工具接口,用来防止 NullPointerException 产生。我们在这里快速地浏览一下 Optional 的工作原理。

Optional 是一个简单的值容器,这个值可以是 null,也可以是 non-null。考虑到一个方法可能会返回一个 non-null 的值,也可能返回一个空值。为了不直接返回 null,我们在 Java8 中就返回一个 Optional。

生成对象

// 构造器是私有的,可通过 of 方法生成非 null 对象。
Optional<String> optional = Optional.of("bam");  // 参数不能为空

// empty 生成空对象
Optional<String> opnull = Optional.empty();

// ofNullable,即可生成空对象又可生成非空对象
Optional<String> ofNullable = Optional.ofNullable("bam");

方法

optional.get();                 // "bam" // 如果此 optional 中存在值,则返回值,否则抛出 NoSuchElementException。

ifPresent

optional.isPresent();           // true  // 如果存在值,则返回 true,否则返回 false。

// 如果存在值,则使用值调用指定的使用者,否则不执行任何操作。
optional.ifPresent((s) -> System.out.println(s.charAt(0)));     // "b"

// 源码
public boolean isPresent() {
    return value != null;
}
public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
        consumer.accept(value);
}

orElse,orElseGet,orElseThrow

optional.orElse("fallback");    // "bam" // 返回值(如果存在),否则返回"fallback"。
Supplier<String> ss = String::new;
opnull.orElseGet(ss); // 返回值(如果存在),否则调用other并返回该 Supplier.get() 的结果。
opnull.orElseThrow(()->new NullPointerException());  // 返回值(如果存在),否则会抛出异常

// 源码
public T orElse(T other) {
    return value != null ? value : other;
}
public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
}
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}

map

如果当前 Optional 为 Optional.empty,则依旧返回 Optional.empty;否则返回一个新的 Optional,该 Optional 包含的是:函数 mapper 在以 value 作为输入时的输出值。可以多次使用 map 操作:

ofNullable.map(s->s.toUpperCase()).map(s -> s.replace("A", "AA")); // BAAM

// 源码
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Optional.ofNullable(mapper.apply(value));
    }
}

flatMap

flatMap 方法与 map 方法的区别在于,map 方法参数中的函数 mapper 输出的是值,然后 map 方法会使用 Optional.ofNullable 将其包装为 Optional;而 flatMap 要求参数中的函数 mapper 输出的就是 Optional。

ofNullable.map(s->s.toUpperCase()).flatMap(s -> Optional.of(s.replace("A", "AA"))); // BAAM

// 源码
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Objects.requireNonNull(mapper.apply(value));
    }
}

filter

filter 方法接受一个 Predicate 来对 Optional 中包含的值进行过滤,如果包含的值满足条件,那么还是返回这个 Optional;否则返回 Optional.empty。

ofNullable.filter(s->s.startsWith("b"));  // bam

// 源码
public Optional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    if (!isPresent())
        return this;
    else
        return predicate.test(value) ? this : empty();
}

参考

https://wizardforcel.gitbooks.io/modern-java/content/ch1.html
https://www.jianshu.com/p/82ed16613072


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 bin07280@qq.com

文章标题:Java 8新特性(3) 内置函数式接口

文章字数:2.4k

本文作者:Bin

发布时间:2019-03-13, 21:08:22

最后更新:2019-08-27, 23:39:18

原始链接:http://coolview.github.io/2019/03/13/Java8/Java%208%E6%96%B0%E7%89%B9%E6%80%A7(3)%20%E5%86%85%E7%BD%AE%E5%87%BD%E6%95%B0%E5%BC%8F%E6%8E%A5%E5%8F%A3/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录