【问题标题】:How to perform nested 'if' statements using Java 8/lambda?如何使用 Java 8/lambda 执行嵌套的“if”语句?
【发布时间】: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());

【问题讨论】:

    标签: java lambda java-8 functional-programming nested-if


    【解决方案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");
        }
    };
    

    【讨论】:

    • 但是可以使用mapfilter 等来实现吗?我正在尝试学习 lambda 函数的基础知识。谢谢。
    • @Z-1 我不确定过滤器是否能够做到这一点,但语法是.filter( i -&gt; { return yourLogic; } )
    • @Z-1 一个 lambda 表达式源于使用 功能接口(一个只有 1 个abstract 方法的接口,例如Runnable;可能有多个default 方法)。例如,Thread 在其构造函数中接受 Runnable。我们可以写new Thread(() -&gt; { });。您甚至可以创建自己的功能接口。所以回答“可以使用mapfilter”:。它适用于 所有 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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-02
        • 2020-09-06
        • 2016-09-15
        • 2022-08-18
        • 1970-01-01
        相关资源
        最近更新 更多