【问题标题】:Java 8 : functional way to write sort, filter and count at same timeJava 8:同时编写排序、过滤和计数的函数式方法
【发布时间】:2019-08-07 18:08:22
【问题描述】:

我对 Java 很陌生,我正在尝试以函数式的方式编写以下逻辑。

我有一个对象列表,其中包含许多字段。 List<someObject> 目前感兴趣的领域是long timestampString bookType

问题陈述是 - 我想在给定列表中找到与具有最低时间戳的 bookType 相同的对象的数量。

例如,如果我们根据timestamp对给定的对象列表进行升序排序,并且排序列表中的第一个对象具有bookType字段为SOMETYPE;然后我想用bookTypeSOMETYPE找出列表中有多少对象

我已经使用普通的旧非函数方式编写了这个逻辑,通过维护 2 个临时变量,然后遍历列表一次以找到最低的 timestamp 和相应的 bookType 以及每个 bookType 的计数

但这在 lambda 中运行是不可接受的,因为它要求变量为 final

我只能写出可以根据timestamp对给定列表进行排序的部分

n.stream().sorted(Comparator.comparingLong(someObject::timestamp)).collect(Collectors.toList());

我被困在如何继续查找最低 timestamp bookType 的计数

【问题讨论】:

标签: java java-8 functional-programming java-stream


【解决方案1】:

但这在 lambda 中运行是不可接受的,因为它要求变量是最终的

首先 - 这不是问题,因为您可以通过创建例如变量Effectively final。单个条目数组并将其单个(第一个)对象传递给 lambda

第二件事是将所有内容放在一个 lambda 中基本上是没有意义的 - 想一想,在逻辑上找到 min 值与按某些属性分组的计数对象有什么联系? 不是 - 将此(以某种方式)放到一个流中只会混淆您的代码

你应该做什么 - 你应该准备方法来找到 min 值并返回它是 bookType 然后流集合并按 bookType 分组并返回具有给定键值的集合的大小

它可能看起来像这个划痕:

public class Item {
    private final long timestamp;
    private final String bookType;

    // Constructors, getters etc
}

// ...

public int getSizeOfBookTypeByMinTimestamp() {
    return items.stream()
        .collect(Collectors.groupingBy(Item::getBookType))
        .get(getMin(items))
        .size();
}

private String getMin(List<Item> items) {
    return items
        .stream()
        .min(Comparator.comparingLong(Item::getTimestamp))
        .orElse( /* HANDLE NO OBJECT */ ) // you can use also orElseThrow etc
        .getBookType();
}

【讨论】:

  • 非常感谢您的指导。
  • 将所有内容收集到Map&lt;String,List&lt;Item&gt;&gt; 中,只是为了获得单个列表的大小,这是非常低效的。通过使用Collectors.groupingBy(Item::getBookType, Collectors.counting()),您将省略List&lt;Item&gt; 的创建,但首先计算。尽管如此,通过计算不相关的事情会做太多的工作。只需先执行String minType = getMin(items);,然后执行return items.stream() .filter(item -&gt; item.getBookType().equals(minType)) .count();。请注意,count() 返回 long,因此如果需要 int,则需要强制转换。
【解决方案2】:

最好的方法是首先找到具有最低时间戳的项目,然后过滤列表中具有匹配时间戳的项目。所以分两步:

Book first = n.stream().min(Comparator.comparingLong(someObject::timestamp).orElseThrow(NoSuchElementException::new);
List<Book> result = n.stream().filter(b -> b.timestamp.equals(first.timestamp)).collect(Collectors.toList());

【讨论】:

  • op 想要匹配的 bookType,而不是时间戳,不是吗?所以你的第二个流应该是n.stream().filter(b -&gt; b.bookType.equals(first.bookType)).collect(Collectors.toList());
  • 非常感谢您的指导。
猜你喜欢
  • 2018-02-07
  • 2017-04-13
  • 2015-02-22
  • 1970-01-01
  • 1970-01-01
  • 2020-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多