java 接口 this参数_Java BiFunction 接口实例

本文详细介绍了Java 8中的BiFunction接口,通过多个示例展示了如何使用它进行双参数的操作,包括如何使用Lambda表达式、方法引用,以及如何组合BiFunction。文章还讨论了在Stream API中BiFunction的应用,例如在列表合并和数值比较中的使用。
摘要由CSDN通过智能技术生成

原标题:Java BiFunction 接口实例

www.baeldung.com/java-bifunction-interface

1. 简介

Java8 引入了函数式编程,可以把函数作为参数传入实现通用方法。熟知的 Java 8 单个参数函数式接口比如 Function、Predicate 和 Consumer。

这篇教程会介绍如何使用支持两个参数的函数式接口。这样的函数被称为二元函数,在 Java 中使用 BiFunction 函数式接口。

2. 单个参数函数

让我们快速回顾一下如何使用单个参数函数或者一元函数,就像在Stream教程中实现的示例:

List mapped = Stream.of( "hello", "world")

. map(word -> word + "!")

.collect(Collectors.toList);

assertThat(mapped).containsExactly( "hello!", "world!");

上面的单元测试中,map 方法接受1个 Function 类型作为参数,对给定的的输入操作后返回结果。

3. 双参操作

Java Stream 库提供了 reduce 函数,可以组合 Stream 中的元素。在这里定义已接收的数据如何与下一个操作转换。

reduce 接受 BinaryOperator 类型作为参数,支持输入两个类型相同的对象。

假设要求把 Stream 中的数据通过破折号连接起来,下面是几种实现方案。

3.1. 使用 Lambda 表达式

用 Lambda 实现BiFunction,前面是由括号包围的两个参数:

String result = Stream.of( "hello", "world")

.reduce( "", (a, b) -> b + "-"+ a);

assertThat(result).isEqualTo( "world-hello-");

上面的示例中,a、b 两个值是字符串类型。Lambda 实现把两个参数按照要求组合,b 在前,a 在后,中间是破折号。

可以看到 reduce 的第一个参数是空字符串,Stream 中的第一个值会与空字符串连接。

另外可以注意到,Java 类型推断在大多数情况下可以忽略参数类型。在 Lambda 上下文类型不明确的情况下,可以为参数加上类型:

String result = Stream.of( "hello", "world")

.reduce( "", (String a, String b) -> b + "-"+ a);

3.2. 使用 Function

如果上面的算法要求不在结尾加上破折号该怎么处理?可以在 lambda 中编写更多代码,但这可能会让代码变得更杂乱。可以把它抽取成一个函数:

privateString combineWithoutTrailingDash(String a, String b){

if(a.isEmpty) {

returnb;

}

returnb + "-"+ a;

}

然后调用:

String result = Stream.of( "hello", "world")

.reduce( "", (a, b) -> combineWithoutTrailingDash(a, b));

assertThat(result).isEqualTo( "world-hello");

像上面这样,lambda 会调用抽取出来的函数。不仅更易于阅读,而且可以扩充到更复杂的实现。

3.3. 使用方法引用

一些 IDE 会自动提示,把面的 lambda 转换为方法引用,这样读起来会更清晰。

重写上面的代码,改为方法引用:

String result = Stream.of( "hello", "world")

.reduce( "", this::combineWithoutTrailingDash);

assertThat(result).isEqualTo( "world-hello");

方法引用通常让函数式代码自解释性变得更强。

4. 使用 BiFunction

到目前为止,我们介绍了如何对两个相同类型的参数使用函数。BiFunction 接口支持不同参数的类型且返回值可以是第三种类型。

假设要求把两个长度相等的列表合并成一个结果列表,对每对输入值执行操作计算结果:

List list1 = Arrays.asList( "a", "b", "c");

List list2 = Arrays.asList( 1, 2, 3);

List result = newArrayList<>;

for( inti= 0; i < list1.size; i++) {

result.add(list1.get(i) + list2.get(i));

}

assertThat(result).containsExactly( "a1", "b2", "c3");

4.1. 为 Function 增加范型

可以使用 BiFunction 为方法增加范型 combiner:

privatestatic List listCombiner(

List list1, List list2, BiFunction combiner) {

List result = newArrayList<>;

for( inti = 0; i < list1.size; i++) {

result.add(combiner.apply(list1.get(i), list2.get(i)));

}

returnresult;

}

上面的代码包含了三种参数类型:第一个列表中的元素类型为 T,第二个列表中的元素类型为 U,组合函数调用后的元素类型为 R。

调用 BiFunction 的 apply方法 得到结果。

4.2. 调用范型函数

combiner的类型是BiFunction,设计的算法可以处理不同类型的输入和输出。让我们试一下:

List list1 = Arrays.asList( "a", "b", "c");

List list2 = Arrays.asList( 1, 2, 3);

List result = listCombiner(list1, list2, (a, b) -> a + b);

assertThat(result).containsExactly( "a1", "b2", "c3");

也可以用来处理完全不同类型的输入和输出。

让我们加入一个算法,判断列表1中的值是否大于列表2,并生成一个 boolean 结果:

List list1 = Arrays.asList( 1.0d, 2.1d, 3.3d);

List list2 = Arrays.asList( 0.1f, 0.2f, 4f);

List result = listCombiner(list1, list2, (a, b) -> a > b);

assertThat(result).containsExactly( true, true, false);

4.3. BiFunction 方法引用

用上面抽取的方法和方法引用重写上面的代码:

List list1 = Arrays.asList( 1.0d, 2.1d, 3.3d);

List list2 = Arrays.asList( 0.1f, 0.2f, 4f);

List result = listCombiner(list1, list2, this::firstIsGreaterThanSecond);

assertThat(result).containsExactly( true, true, false);

privateboolean firstIsGreaterThanSecond(Double a, Float b){

returna > b;

}

用方法引用加入算法firstIsGreaterThanSecond看起来代码更容易理解一些。

4.4. 使用 this 调用 BiFunction 方法引用

改变一下要求,用上面基于BiFunction算法确认两个列表是否相等:

List list1 = Arrays.asList( 0.1f, 0.2f, 4f);

List list2 = Arrays.asList( 0.1f, 0.2f, 4f);

List result = listCombiner(list1, list2, (a, b) -> a.equals(b));

assertThat(result).containsExactly( true, true, true);

实际上可以简化成下面这样:

List result = listCombiner(list1, list2, Float::equals);

这是因为 Float 中的 equals 与 BiFunction 函数签名相同,第一个隐式参数是 Float 类型,第二个参数是 Object 类型与第一个参数比值。

5. BiFunctions 组合

如果通过方法引用实现数值比较该怎么实现?

如果使用方法引用实现数值列表比较示例会是怎样?

List list1 = Arrays.asList( 1.0d, 2.1d, 3.3d);

List list2 = Arrays.asList( 0.1d, 0.2d, 4d);

List result = listCombiner(list1, list2, Double::compareTo);

assertThat(result).containsExactly( 1, 1, -1);

这个例子与之前的很像,但是返回值类型为 Integer 而非原来的 Boolean。这是因为 Double 中的 compareTo 方法返回类型为 Integer。

这里可以使用 andThen在原来的基础上增加额外的处理。这会生成 BiFunction,先对两个输入执行操作,然后接着执行另一个操作。

接下来,新建一个函数来把Double::compareTo方法引用强制转换为BiFunction:

privatestatic BiFunction asBiFunction(BiFunction function) {

returnfunction;

}

lambda 或者方法引用只在转换后才能变成 BiFunction。可以使用下面 helper 函数把 lambda 显示转换为 BiFunction 对象。

现在,使用andThen扩展现有函数的行为:

List list1 = Arrays.asList( 1.0d, 2.1d, 3.3d);

List list2 = Arrays.asList( 0.1d, 0.2d, 4d);

List result = listCombiner(list1, list2,

asBiFunction(Double::compareTo).andThen(i -> i > 0));

assertThat(result).containsExactly( true, true, false);

6. 总结

本文从 Java Stream 库与自定义函数两个角度探索了 BiFunction 和 BinaryOperator 的用法,了解了如何使用 lambda 和方法引用传递 BiFunction 以及组合函数。

Java 库只提供单个参数和两个参数的函数式接口。需要更多参数,请参阅柯里化获得更多想法。完整的源代码可以在 GitHub 上找到。

github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-8-2返回搜狐,查看更多

责任编辑:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值