如何在使用collect时避免多个流式传输

时间:2015-09-23 06:54:39

标签: java-8 java-stream jooq readability

我有一个使用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流式传输结果然后我流式传输收集的地图。比较器似乎也很突出。当然,我可以用它来制作课程,但也许还有另一种解决方案。

2 个答案:

答案 0 :(得分:5)

我不能说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())));

答案 1 :(得分: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();