Java聚合操作与匿名类建议

时间:2018-01-20 16:03:01

标签: java lambda java-stream

在这个程序中,假设我有一个班级领导者,我想分配给一个班级。任务需要一个技能类,具有类型和力量。领袖有一份技能清单。我想写一个方法,将一个领导者(或一些领导者)分配给一个任务,并检查领导者的综合技能是否足以完成任务。

public void assignLeaderToMission(Mission m, Leader... leaders) {
    List<Leader> selectedLeaders = new ArrayList(Arrays.asList(leaders));
    int combinedStrength = selectedLeaders
            .stream()
            .mapToInt(l -> l.getSkills()
                            .stream()
                            .filter(s -> s.getType() == m.getSkillRequirement().getType())
                            .mapToInt(s -> s.getStrength())
                            .sum())
            .sum();
    if(m.getSkillRequirement().getStrength() > combinedStrength)
        System.out.println("Leader(s) do not meet mission requirements");
    else {
        // assign leader to mission
    }
}

这是使用lambda操作的流的适当方法吗? NetBeans提出了我使用匿名类的建议,但我认为lambas和聚合操作应该用单个方法替换匿名类的需要,或者我可能错误地解释了这个。 在这种情况下,我正在访问List&lt;&gt;在列表中&lt;&gt;我不确定这是否是正确的方法。一些帮助将非常感激。

2 个答案:

答案 0 :(得分:0)

Lambda必须简洁,以便易于维护。如果lambda表达式很长,那么代码将难以维护和理解。即使调试也会更难。 有关Why the perfect lambda expression is just one line的更多详细信息,请参阅此处。

危险的长λ

为了更好地理解编写简短,简洁的lambda表达式的好处,请考虑相反的情况:在几行代码中展开的庞大lambda:

System.out.println(
values.stream()
  .mapToInt(e -> {     
    int sum = 0;
    for(int i = 1; i <= e; i++) {
      if(e % i == 0) {
        sum += i;
      }
    }

    return sum;
  })
  .sum());

尽管此代码是以函数式编写的,但它忽略了函数式编程的好处。让我们考虑一下原因。

<强> 1。它很难阅读

好的代码应该是邀请阅读。这段代码需要精力去阅读:你的眼睛会紧张地找到不同部分的开始和结束。

<强> 2。其目的不明确

好的代码应该像故事一样阅读,而不是拼图。像这样的一长串匿名代码隐藏了其目的的细节,耗费了读者的时间和精力。将这段代码包装到命名函数中会使其模块化,同时通过相关名称显示其目的。

第3。代码质量差

无论您的代码是什么,您都可能希望在某个时候重复使用它。此代码中的逻辑嵌入在lambda中,而lambda又作为参数传递给另一个函数mapToInt。如果我们需要程序中的其他代码,我们可能会想重写它,从而在我们的代码库中引入不一致。或者,我们可能只是复制并粘贴代码。这两种选择都不会产生良好的代码或高质量的软件。

<强> 4。很难测试

代码始终执行键入的内容,而不一定是预期的内容,因此必须测试任何非平凡的代码。如果lambda表达式中的代码不能作为一个单元到达,则它不能进行单元测试。您可以运行集成测试,但这不能替代单元测试,尤其是当代码执行重要工作时。

<强> 5。代码覆盖率不佳

嵌入在参数中的Lambda不容易被提取为单位,并且许多在覆盖率报告中显示为红色。没有洞察力,团队只需要假设这些部分有效。

答案 1 :(得分:0)

在这里使用lambda表达式没有任何问题。 Netbeans只是提供代码转换,因为它是可能的(Netbeans可以为你做转换)。如果您接受该要约并让它转换代码,那么转换完成后很可能会开始提供将匿名类转换为lambda表达式,只是因为它(现在)可能。

但是如果你想改进你的代码,你不应该使用原始类型,即使用

List<Leader> selectedLeaders = new ArrayList<>(Arrays.asList(leaders));

代替。但是,如果您只需要List<Leader>而不需要addremove的支持,则无需将列表复制到ArrayList,因此您可以使用

List<Leader> selectedLeaders = Arrays.asList(leaders);

代替。但是,如果您想要做的只是流式传输数组,则根本不需要List绕道而行。您可以先使用Arrays.stream(leaders)

您也可以使用flatMap来减少嵌套代码的数量,即

int combinedStrength = Arrays.stream(leaders)
    .flatMap(l -> l.getSkills().stream())
    .filter(s -> s.getType() == m.getSkillRequirement().getType())
    .mapToInt(s -> s.getStrength())
    .sum();