如何使用 Java 8/lambda 执行嵌套的“if”语句?
Posted
技术标签:
【中文标题】如何使用 Java 8/lambda 执行嵌套的“if”语句?【英文标题】:How to perform nested 'if' statements using Java 8/lambda? 【发布时间】:2015-10-16 05:39:20 【问题描述】:我有以下代码,并想使用 lambda 函数来实现它,只是为了好玩。可以使用基本的聚合操作来完成吗?
List<Integer> result = new ArrayList<>();
for (int i = 1; i <= 10; i++)
if (10 % i == 0)
result.add(i);
if (i != 5)
result.add(10 / i);
使用 lambda:
List<Integer> result = IntStream.rangeClosed(1, 10)
.boxed()
.filter(i -> 10 % i == 0)
// a map or forEach function here?
// .map(return 10 / i -> if i != 5)
.collect(Collectors.toList());
【问题讨论】:
【参考方案1】:这里的基本观察是您的问题涉及非同构转换:单个输入元素可能映射到零、一个或两个输出元素。每当您注意到这一点时,您应该立即开始寻找涉及flatMap
而不是map
的解决方案,因为这是实现这种通用转换的唯一方法。在您的特定情况下,您可以首先将filter
应用于一对零元素映射,然后将flatMap
应用于一对二映射:
List<Integer> result =
IntStream.rangeClosed(1, 10)
.filter(i -> 10 % i == 0)
.flatMap(i -> i == 5 ? IntStream.of(i) : IntStream.of(i, 10 / i))
.boxed()
.collect(toList());
(假设import static java.util.stream.Collectors.toList
)
【讨论】:
我喜欢您不仅回答问题的方式,而且还教您如何思考问题以找到解决方案。【参考方案2】:您可以为 lambda 声明一个主体。例如:
Runnable run = () -> System.out.println("Hey");
可能
Runnable run = () ->
System.out.println("Hey");
;
在该主体中,您可以创建嵌套语句:
Runnable run = () ->
int num = 5;
if(num == 5)
System.out.println("Hey");
;
【讨论】:
但是可以使用map
、filter
等来实现吗?我正在尝试学习 lambda 函数的基础知识。谢谢。
@Z-1 我不确定过滤器是否能够做到这一点,但语法是.filter( i -> return yourLogic; )
@Z-1 一个 lambda 表达式源于使用 功能接口(一个只有 1 个abstract
方法的接口,例如Runnable
;可能有多个default
方法)。例如,Thread
在其构造函数中接受 Runnable
。我们可以写new Thread(() -> );
。您甚至可以创建自己的功能接口。所以回答“可以使用map
和filter
”:是。它适用于 所有 lambdas。【参考方案3】:
当您尝试将元素添加到管道或一对多映射中时,请使用 flatMap
。地图是一对一的映射。
ArrayList<Integer> result = (ArrayList<Integer>) IntStream.rangeClosed(1, 10)
.boxed()
.filter(i -> 10 % i == 0)
.flatMap((Integer i) -> return i!=5 ? Stream.of(i, (10/i)):Stream.of(i);)
.collect(Collectors.toList());
这会产生与
相同的列表ArrayList<Integer> result2 = new ArrayList<Integer>();
for (int i = 1; i <= 10; i++)
if (10 % i == 0)
result2.add(i);
if (i != 5)
result2.add(10 / i);
如果您想知道哪种方式更快,循环方法比使用流快约 3 倍。
Benchmark Mode Cnt Score Error Units
testStreams.Bench.loops avgt 5 75.221 ± 0.576 ns/op
testStreams.Bench.streams avgt 5 257.713 ± 13.125 ns/op
【讨论】:
这很有趣。感谢您的基准。我也注意到,Streams 比传统的 for 循环慢得多。 实际上取决于应用程序,对整数的操作是您可以做的一些最简单的操作,因为您在这里所做的设置流的开销太高了。我发现this post 上的第二个答案很有帮助。 随着循环范围变大,流开销确实变小了。不过在这种情况下并没有完全消失。【参考方案4】:你可以这样做:
List<Integer> result1 = IntStream
.rangeClosed(1, 10)
.boxed()
.filter(i -> 10 % i == 0)
.map(i -> (i != 5 ? Stream.of(i, 10 / i) : Stream.of(i)))
.flatMap(Function.identity())
.collect(Collectors.toList());
【讨论】:
【参考方案5】:尝试使用flatMap
:
List<Integer> result = IntStream.rangeClosed(1, 10)
.boxed()
.flatMap((i) ->
List<Integer> results = new ArrayList<>();
if (10 % i == 0)
results.add(i);
if (i != 5)
results.add(10 / i);
return results.stream();
)
.collect(Collectors.toList());
见http://ideone.com/EOBiEP
【讨论】:
以上是关于如何使用 Java 8/lambda 执行嵌套的“if”语句?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Java 8 Lambda 将对象列表转换为 Map<Object, Object>
如果使用我的服务使用Java 8 lambda / streams列表不为空,如何从列表中删除每个元素