3.4 使用函数式接口

Java API中已有的函数式接口:Comparable、Runnable和Callable。

3.2.2 函数描述符所示,Java8在java.time.function定义了一些常用的函数式接口。

3.4.1 Predicate

T -> boolean

// jdk8
@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

静态泛型方法——列表过滤

public static <T> List<T> filter(List<T> list, Predicate<T> p) {
    List<T> result = new ArrayList<>();
    for (T ele : list) {
        if (p.test(ele)) {
            result.add(ele);
        }
    }
    return result;
}

List<String> listOfStrings = Lists.newArrayList("", "123", "abc");
Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
filter(listOfStrings, nonEmptyStringPredicate); // [123,  abc]

3.4.2 Consumer

T -> void

// jdk8
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

静态泛型方法——列表循环执行

public static <T> void forEach(List<T> list, Consumer<T> c) {
    for (T ele : list) {
        c.accept(ele);
    }
}

// 1   2   3   4   5   
forEach(Lists.newArrayList(1, 2, 3, 4, 5), (Integer i) -> System.out.print(i + "\t"));

3.4.3 Function

T -> R

// jdk8
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

静态泛型方法——列表对象映射

public static <T, R> List<R> map(List<T> list, Function<T, R> f) {
    List<R> result = new ArrayList<>();
    for (T ele : list) {
        result.add(f.apply(ele));
    }
    return result;
}


// [7, 2, 6]
List<Integer> result = map(Lists.newArrayList("lambdas", "in", "action"), (String s) -> s.length());

基本类型函数式接口

由于Java泛型只能绑定引用类型,不能作用于基本类型。

为提高性能和减少内存使用,如3.2.2 函数描述符所示,Java8在java.time.function提供了基本类型函数式接口。

// jdk8
@FunctionalInterface
public interface IntPredicate {
    boolean test(int value);
}
Predicate<Integer> evenIntegers = (Integer i) -> i % 2 == 0;
// true,装箱
evenIntegers.test(1000);

// true,无装箱
IntPredicate evenInts = (int i) -> i % 2 == 0;
evenInts.test(1000);

若标准函数式接口,无法满足诉求,可按照函数描述符形如(T, U)-> R进行思考及设计。

测验3.4:函数式接口

对于下列函数描述符(即Lambda表达式的签名),你会使用哪些函数式接口?

在表3-2中可以找到大部分答案。

作为进一步练习,请构造一个可以利用这些函数式接口的有效Lambda表达式:

  1. T -> R,Function<T, R>
  2. (int, int) -> int,IntBinaryOperator
  3. T -> void,Consumer<T>
  4. () -> T,Supplier<T> 或者 Callable<T>(需要处理抛出的异常)
  5. (T, U) -> R,BiFunction<T, U, R>

java.time.function中所有的函数式接口都不允许抛出受检异常,因此若需处理抛出异常的Lambda表达式

  1. 定义新的函数式接口,声明受检异常。例如示例3.3;

    @FunctionalInterface
    public interface BufferedReaderProcessor {
        String process(BufferedReader br) throws IOException;
    }
    
    BufferedReaderProcessor p = (BufferedReader br) -> br.readLine();
    
  2. try-catch显式捕获处理异常;

    Function<BufferedReader, String> bufferedReaderFunction = (BufferedReader br) -> {
        try {
            return br.readLine();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    };
    
posted @ 2023-06-28 17:41  夜是故乡明  阅读(4)  评论(0编辑  收藏  举报