zoukankan      html  css  js  c++  java
  • Java 8 函数接口详细教程

    ay = new byte[array.length];
    for (int i = 0; i < array.length; i++) {
    transformedArray[i] = function.applyAsByte(array[i]);
    }
    return transformedArray;
    }
    1
    2
    3
    4
    5
    6
    7
    这里测试如何实现short数组至byte数组乘以2的转换:

    short[] array = {(short) 1, (short) 2, (short) 3};
    byte[] transformedArray = transformArray(array, s -> (byte) (s * 2));

    byte[] expectedArray = {(byte) 2, (byte) 4, (byte) 6};
    assertArrayEquals(expectedArray, transformedArray);
    1
    2
    3
    4
    5
    二元函数接口
    带两个参数的lambda表达式,我们需要使用名称包含Bi关键字的函数接口:BiFunction, ToDoubleBiFunction, ToIntBiFunction, and ToLongBiFunction。

    BiFunction 两个参数和返回值都是泛型,而ToDoubleBiFunction和其他类似函数接口可以返回基本类型。

    使用二元lambda表示的典型示例是jdk中Map.replaceAll 方法,其使用计算值替换map中所有值。下面使用BiFunction实现接收key和被替换的值取计算新值并返回:

    Map<String, Integer> salaries = new HashMap<>();
    salaries.put("John", 40000);
    salaries.put("Freddy", 30000);
    salaries.put("Samuel", 50000);

    salaries.replaceAll((name, oldValue) ->
    name.equals("Freddy") ? oldValue : oldValue + 10000);
    1
    2
    3
    4
    5
    6
    7
    Supplier函数接口
    Supplier接口是另一个不带任何参数的特殊形式。典型用于延迟生成值。举例,定义double值得平方函数。其不接收一个值,而是Supperlier作为值:

    public double squareLazy(Supplier<Double> lazyValue) {
    return Math.pow(lazyValue.get(), 2);
    }
    1
    2
    3
    该函数可以通过使用Supplier实现来延迟生成值。这对于生成值需要花费很多时间情况非常有用。下面使用Guava 的sleepUninterruptibly 的方法进行模拟:

    Supplier<Double> lazyValue = () -> {
    Uninterruptibles.sleepUninterruptibly(1000, TimeUnit.MILLISECONDS);
    return 9d;
    };

    Double valueSquared = squareLazy(lazyValue);
    1
    2
    3
    4
    5
    6
    另一个Supplier的使用场景是定义流的生成序列逻辑。为了演示,我们使用静态Stream.genernate方法创建斐波那契数值流:

    int[] fibs = {0, 1};
    Stream<Integer> fibonacci = Stream.generate(() -> {
    int result = fibs[1];
    int fib3 = fibs[0] + fibs[1];
    fibs[0] = fibs[1];
    fibs[1] = fib3;
    return result;
    });
    1
    2
    3
    4
    5
    6
    7
    8
    Stream.generate方法传入函数作为Supplier函数接口的实现。注意,要成为有用的生成器,Supplier函数接口通常需要某种外部状态。在本例中,它的状态由最后两个斐波那契数列数字组成。
    为了实现该状态,我们使用一个数组而不是一组变量,因为所有在lambda表达式里面使用的外部变量必须是final。

    其他特殊的Supplier 函数接口包括 BooleanSupplier, DoubleSupplier, LongSupplier 和 IntSupplier, 它们的返回类型都是相应的基本类型。

    Consumer 函数接口
    与Supplier相反,Consumer接口接收一个泛型参数但没有返回值。该函数是有副作用的代表(因为修改了参数,lambda表达式不能修改参数)。

    举例,对list中每个名称以输出至控制台的方式进行问候。lambda表达式传入 List.forEach方法实现Consumer函数接口:

    List<String> names = Arrays.asList("John", "Freddy", "Samuel");
    names.forEach(name -> System.out.println("Hello, " + name));
    1
    2
    也有特定版本的Consumer — DoubleConsumer, IntConsumer and LongConsumer,接收基本类型值作为参数。更有趣的是BiConsumer接口,其中一个应用场景是迭代map的entry:

    Map<String, Integer> ages = new HashMap<>();
    ages.put("John", 25);
    ages.put("Freddy", 24);
    ages.put("Samuel", 30);

    ages.forEach((name, age) -> System.out.println(name + " is " + age + " years old"));
    1
    2
    3
    4
    5
    6
    另外一组特殊BiConsumer 接口是 ObjDoubleConsumer, ObjIntConsumer, ObjLongConsumer ,分别接收两个参数,其中之一是泛型,另一个是基本类型。

    Predicate 函数接口
    在数学逻辑中,谓词是一个函数,它接收一个值并返回一个布尔值。Predicate函数接口是一个特殊函数接口,其接收一个泛型类型值,返回一个boolean。典型的应用场景是过滤集合的值:

    List<String> names = Arrays.asList("Angela", "Aaron", "Bob", "Claire", "David");

    List<String> namesWithA = names.stream()
    .filter(name -> name.startsWith("A"))
    .collect(Collectors.toList());
    1
    2
    3
    4
    5
    在上面的代码中,我们使用流API过滤list的值名称以A开头的,Predicate实现即过滤逻辑代码。和前面示例一样,IntPredicate, DoublePredicate 和 LongPredicate 几个接口接收基础类型。

    Operator 函数接口
    Operator 接口是Function接口的特殊情况,接收和返回类型相同。UnaryOperator接口接收单个参数,其中一个应用是Collection Api的替换list中所有值,使用相同类型的计算值:

    List<String> names = Arrays.asList("bob", "josh", "megan");
    names.replaceAll(name -> name.toUpperCase());
    1
    2
    List.replaceAll函数返回void类型,因为其替换一定位置的值。为了实现该目的,用于转换list值的lambda必须返回与其入参类型相同的结果。这就是为什么UnaryOperator在这里很有用。当然也可以使用方法引用代替lambda:

    names.replaceAll(String::toUpperCase);
    1
    BinaryOperator接口一个最有趣的用例是reduce操作。如计算整型集合值之和。使用stream api可以实现,但更通用的方式是使用reduce方法:

    List<Integer> values = Arrays.asList(3, 5, 8, 9, 12);

    int sum = values.stream().reduce(0, (i1, i2) -> i1 + i2);
    1
    2
    3
    reduce方法接收一个初始累加值和BinaryOperator函数接口。该接口参数是相同类型的一对值,函数包括逻辑实现连接两者称为一个相同类型的值。传入函数必须具有结合性,即与值得计算顺序无关,如应满足下面条件:

    op.apply(a, op.apply(b, c)) == op.apply(op.apply(a, b), c)
    1
    BinaryOperator 函数的结合性使得并行计算很容易。当然也针对基本类型的UnaryOperator 和 BinaryOperator,依次命名为 DoubleUnaryOperator, IntUnaryOperator, LongUnaryOperator, DoubleBinaryOperator, IntBinaryOperator 和 LongBinaryOperator。

    传统的函数接口
    不是所有的函数接口都来自Java 8 。很多之前版本的接口满足函数接口的条件则可以用作lambda表达式。典型的例子是并行API的 Runnable 和 Callable 接口。在Java 8 中这些接口使用@FunctionalInterface进行标记,这使得并发代码大大得到简化:

    Thread thread = new Thread(() -> System.out.println("Hello From Another Thread"));
    thread.start();
    1
    2
    总结
    本文我们描述Java Api提供可以作为lambda表达的不同函数式接口,并通过示例说明其应用场景。
    --------------------- 

  • 相关阅读:
    HDU4507 吉哥系列故事――恨7不成妻(数位dp)
    UCF Local Programming Contest 2017 G题(dp)
    ICPC Latin American Regional Contests 2019 I题
    UCF Local Programming Contest 2017 H题(区间dp)
    HDU2089 不要62
    AcWing1084 数字游戏II(数位dp)
    UCF Local Programming Contest 2017 F题(最短路)
    Google Code Jam 2019 Round 1A Pylons(爆搜+贪心)
    AcWing1083 Windy数(数位dp)
    Vue
  • 原文地址:https://www.cnblogs.com/ly570/p/10954610.html
Copyright © 2011-2022 走看看