【问题标题】:How to avoid multiple streaming when using collect使用收集时如何避免多次流式传输
【发布时间】:2015-12-20 09:04:50
【问题描述】:

我结合使用 jooq 查询数据库和使用流对结果进行后处理。但是我觉得我的代码不是很可读,也不够简洁。如何以更好地表达我的意图的方式改进我的代码。

sql
    .select(field("USER_NAME", String.class))
    .from(table("CWD_USER"))
    .fetch()
    .stream()
    .map(f -> f.getValue(field("USER_NAME", String.class)))
    .collect(Collectors.groupingBy(s -> StringUtils.split(s, "-")[0], Collectors.counting()))
    .entrySet().stream()
    .sorted(new java.util.Comparator<Entry<String, Long>>() {
        @Override
        public int compare(Entry<String, Long> o1,
                Entry<String, Long> o2) {
            return o2.getValue().compareTo(o1.getValue());
        }
    })
    .forEach(e -> System.out.println(String.format("%13s: %3d", e.getKey(), e.getValue())));

首先,我遇到了多流媒体的问题。我首先从 jooq 流式传输结果,然后流式传输收集的地图。比较器似乎也很突出。当然我可以用它来做一门课,但也许还有另一种解决方案。

【问题讨论】:

  • 即使您不知道Map.Entry.comparingByValue(…) 的存在,我也不明白您为什么认为必须为Comparator 使用内部类,正如您已经证明的那样了解代码中其他位置的 lambda 表达式。
  • 仅供参考,对应的 lambda 应该是 .sorted( (o1, o2) -&gt; o2.getValue().compareTo( o1.getValue() ) )。感谢@Holger 指出这一点。
  • I first stream the result from jooq then I stream the collected map - 没有。您从 jooq 流式传输结果,仅此而已。您的示例中没有显示其他流,即一个带有几个中间操作和一个终端操作的单个流。这就是流的工作方式。如果你想“避免”流的核心功能,你需要使用经典的 foreach/for/while - 循环。但老实说:那将是一个降级......流非常简洁和漂亮 - 你自己的代码证明了这一点。相同的功能需要至少 100 行没有流的代码。
  • @specializt:仔细看看。中间有一个collect。这是第一个流的终端操作,entrySet().stream() 创建一个新流。没关系,因为这是不可避免的。
  • 中间映射是不可避免的,尤其是后面的排序,因为这些操作必须在管道中的下一步执行之前完成,否则它无法知道它是否已经找到 min-元素

标签: java-8 java-stream jooq readability


【解决方案1】:

我不能说 JOOQ 部分,但 Stream API 部分看起来不错。您必须在中间收集才能在排序之前知道计数。请注意,此类比较器已在 JDK 中实现:它是 Map.Entry.comparingByValue()。可以使用(加Comparator.reverseOrder()参数倒序排序):

sql
    .select(field("USER_NAME", String.class))
    .from(table("CWD_USER"))
    .fetch()
    .stream()
    .map(f -> f.getValue(field("USER_NAME", String.class)))
    .collect(Collectors.groupingBy(s -> StringUtils.split(s, "-")[0], Collectors.counting()))
    .entrySet().stream()
    .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
    .forEach(e -> System.out.println(String.format("%13s: %3d", e.getKey(), e.getValue())));

【讨论】:

    【解决方案2】:

    除非这是一个更复杂查询的大幅简化版本,否则我会将所有逻辑移至 SQL。等效的 SQL 查询(使用 Oracle 方言)是:

    SELECT PREFIX, COUNT(*)
    FROM (
      SELECT SUBSTR(USER_NAME, 1, INSTR(USER_NAME, '-') - 1) AS PREFIX
      FROM CWD_USER
    ) T
    GROUP BY PREFIX
    ORDER BY COUNT(*)
    

    或者,使用 jOOQ:

    sql.select(field("PREFIX", String.class), count())
       .from(
         select(substring(
           field("USER_NAME", String.class), 
           inline(1), 
           position(field("USER_NAME", String.class), inline("-")).sub(inline(1))
         ).as("PREFIX"))
         .from(table("CWD_USER"))
       )
       .groupBy(field("PREFIX", String.class))
       .orderBy(count())
       .fetch();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-26
      • 1970-01-01
      • 2021-10-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多