java - 无法理解 lambda 和 longstream 方法

标签 java

我有这样的代码示例。

import java.util.LinkedList;
import java.util.List;
import java.util.stream.LongStream;

public class RemovedNumbers {

    public static List<long[]> removNb(long n) {
        System.out.println(n);
        long sum = ((n + 1) * n / 2);
        long minMultiplication = sum - 2 * n + 1;
        long minCandidate = (long) Math.sqrt(minMultiplication);

        LinkedList<long[]> list = new LinkedList<>();

        LongStream.rangeClosed(minCandidate, n)
                  .mapToObj(a -> new long[]{a, calculateB(a, sum)})
                  .filter(longs -> longs[0] > longs[1])
                  .filter(longs -> longs[1] <= n)
                  .filter(longs -> longs[0] * longs[1] == sum - longs[0] - longs[1])
                  .forEach(longs -> addArrays(list, longs));

        return list;
    }

    private static long calculateB(long a, long sum) {
        return (sum - a) / (a + 1);
    }

    private static void addArrays(final LinkedList<long[]> list, final long[] longs) {
        list.addFirst(new long[]{longs[1], longs[0]});
        list.add(longs);
    }
}

这段代码在 LongStream 部分对我来说很复杂。 我没有得到一些积分,所以我需要帮助:

  1. 我检查了 LongStream 类。
  2. 该类使用四种方法:rangeClosed、mapToObj、filter、forEach(我在 Java 文档中找到了它们的描述)。不幸的是,现在我开始研究java 1.8版本,所以我无法理解它是如何工作的以及发生了什么。
  3. 出现在哪里"a"在mapToObj 中?它是什么?我没有看到 var "a"代码前面部分的声明。
  4. 据我所知,lambda 是通过这样的方案生成的: (arguments) -> (body) 。所以"a"是一个参数,"new long[]..." - 是一个 body 。这部分不会给我带来任何问题。但下一个是 "longs" - 参数,“longs[0] > longs[1]” - 主体,引起一些问题。什么是变量 "longs" ?以前没有声明过!它看起来如何?怎么运行的?
  5. LongStream 类可以写在一行中,我说得对吗?喜欢:LongStream.rangeClosed().filter().filter().filter().forEach(); ?
  6. 所有方法都会按顺序执行,我说得对吗?彼此?首先rangeClosed,然后mapToObj,然后filter...或者还有其他顺序吗?

非常感谢!

最佳答案

你的第三点回答了你的第二点 - a 是传递给 mapToObj 的 lambda 表达式的参数。

如果你能理解这一点,那么你的第四点也应该很容易理解。 longs 是传递给 filter 的 lambda 表达式的参数。请记住,您可以随意命名参数名称。我猜代码作者之所以将参数重命名为longs,是因为在上一行中,流中的每个long都被映射为一个long[ ],所以现在它是一个长数组流。

Am I right that LongStream class can be writes in one line?

是的,但最终会得到超长的代码行,所以我们几乎从不这样做。

Am I right that all methods execute consequently? By each other? The first rangeClosed, then mapToObj, then filter... or is there another order?

按该顺序调用方法,但它们执行的操作不会立即运行。这是流最酷的部分。当您执行终端操作 forEach 时,长整数只会被 mapToObj' 和 filter' 编辑。换句话说,mapToObjfilter 有点像在说“这就是这个流应该做的事情......”,当您执行 forEach 时,你是在说“现在就做吧!”

如果您仍然不明白流正在做什么,请尝试将它们视为工厂中的生产线。一开始,传送带上有。然后它们通过一台机器,将它们每个都转换成一个long[]。之后,它们通过三个过滤器。这些过滤器会将它们推离传送带,除非长阵列满足某些条件。

编辑:

如果您想在不使用 lambda 的情况下编写此代码,则可以使用匿名类来编写它:

LongStream.rangeClosed(minCandidate, n)
        .mapToObj(new LongFunction<long[]>() {
            @Override
            public long[] apply(long a) {
                return new long[]{a, calculateB(a, sum)};
            }
        })
        .filter(new Predicate<long[]>() {
            @Override
            public boolean test(long[] longs) {
                return longs[0] > longs[1] && 
                        longs[1] <= n && 
                        longs[0] * longs[1] == sum - longs[0] - longs[1];
            }
        })
        .forEach(new Consumer<long[]>() {
            @Override
            public void accept(long[] longs) {
                addArrays(list, longs);
            }
        });

关于java - 无法理解 lambda 和 longstream 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56312781/

相关文章:

java - 如何使用 Jsoup 选择器 "not"

java - Java 8 示例未返回预期输出 'Test Passed'

java - 每次 JAVAC 在 Ubuntu 12.04 中工作时都明确需要重新加载系统范围的 PATH ./etc/profile

java - 关于 JPA spec jar (javax.persistence.jar) 的问题

java - Spring HATEOAS 嵌入式资源支持

java - 如何使用 Velocity API 获取静态(非模板)内容?

java - 如何在我的程序中将 double 格式化为整数?棋盘米传奇

java - 登录后禁用 JSP 中的后退按钮?

java - 将枚举字段映射到具有非零开始值的数字列

java - 无法使用JSP从mySQL数据库获取数据