【问题标题】:Understanding functional operator: Lambda了解函数运算符:Lambda
【发布时间】:2014-08-14 10:37:24
【问题描述】:

我有一个名为 Semester of Semester objects 的数组列表

private ArrayList<Semester> Semesters

我编写了以下代码来使用列表(学期)中的对象(学期)打印出一个字符串

String report = year + "\n";
for (Semester s : Semesters) {
    report += s.toString() + "\n";
}

然后我得到一个关于netbeans的提示,上面的整个代码可以像这样写在一行中:

String report = year + "\n";
report = Semesters.stream().map((s) -> s.toString() + "\n").reduce(report, String::concat);

我是一名中级 Java 学生,我正在尝试理解这个功能,我发现它非常有用,但我无法完全理解它。

请帮助我理解这两段代码的相同之处。

【问题讨论】:

    标签: java string arraylist lambda


    【解决方案1】:

    我没有使用过 Java lambda,但是通过函数式编程范式中的 map 和 reduce\fold 操作,这就是 2 个 sn-ps 的等效方式:

    1. map 基本上将特定函数应用于集合中的每个元素。在这种情况下,该函数/方法是s.toString() + "\n"。这与遍历集合并通过 foreach 循环将函数应用于每个元素相同。
    2. reduce 是一个折叠操作,即将 map 操作返回的每个元素连接到原始字符串 report。

    所以在你的原始代码中

    String report = year + "\n";
    for (Semester s : Semesters) {
        report += s.toString() + "\n";
    }
    

    您基本上对元素s 进行操作,然后将该操作的结果连接到report。使用 lambda,首先在map 阶段对整个集合进行操作,然后在映射过程中遍历返回的集合,并在reduce 阶段将每个元素连接到report。

    【讨论】:

      【解决方案2】:

      以下是使用匿名类分解的等效功能:

      Function<Semester, String> toStrFn = new Function<Semester, String>() {
        @Override
        public String apply(Semester semester) {
          return semester + "\n";
        }
      };
      
      BinaryOperator<String> reducer = new BinaryOperator<String>() {
        @Override
        public String apply(String lastResult, String currentValue) {
          return lastResult.concat(currentValue);
        }
      };
      
      String report = year + "\n";
      Stream<Semester> semesterStream = Semesters.stream();
      Stream<String> stringStream = semesterStream.map(toStrFn);
      report = stringStream.reduce(report, reducer);
      

      【讨论】:

        【解决方案3】:
        • semesters.stream() 将提供一个 Stream&lt;Semester&gt; 对象供一次性使用(有状态的,如迭代器)。
        • .map(...) 被赋予了一个函数接口:一个只有一个参数类型为 Semester 的方法的接口。
        • lambda exoression 将生成一个生成接口的实例,其中包含一个以 Semester 参数和 String 作为结果类型的方法。
        • 因此地图产生一个流
        • Map 稍后将遍历 Semester-s,应用方法并收集字符串。
        • Stream&lt;String&gt;.reduce(String startValue, stepFunction) 将让操作(迭代)开始收集单个字符串,初始化为 startValue,每一步:`result = result.concat(map 方法的返回值)。

        我希望我的解释是正确的。

        System.out.println("Mapping Semester to String...");
        Stream<String> sems = Semesters.stream().map((s) -> {
                System.out.println("map call " + s);
                return s + "\n";
            });
        System.out.println("Reducing String stream to String...");
        String report = sems.reduce(year + "\n", String::concat);
        

        上面显示了急切/懒惰的评估。也许看看 Builder Pattern,看看引擎盖下发生了什么。试试parallel 和filter。

        String report = year + "\n"
            + semesters.stream()
                .filter(...)
                .sorted(...)
                .map(Semester::toString)
                .collect(Collectors.joining("\n"));
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-07-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-13
          相关资源
          最近更新 更多