【问题标题】:How to combine unlike streams in Java 8如何在 Java 8 中组合不同的流
【发布时间】:2014-10-02 00:17:57
【问题描述】:

我有一个Set<DateCount>,我使用以下代码创建它。这将创建一组 7 个 DateCount 对象,初始计数为 0,从当天开始,对应于当前周的每一天。

// Create an initial Set of DateCount objects for the current week with counts of 0
Set<DateCount> dateCounts = IntStream.range(0, DAYS_IN_WEEK)
        .mapToObj(idx -> new DateTime().withTimeAtStartOfDay().plusDays(idx))
        .map(dt -> new DateCount(dt.toDate(), 0L))
        .collect(toSet());

我有一个从数据库存储库返回的List&lt;Object[]&gt;。列表中的每个Object[] 在索引0 处都有一个BigDecimal,在索引1 处有一个LongBigDecimal 实际上是一个日期,类似于20141001。我想知道是否有一种方法可以以流方式使用此数据更新dateCounts 集。现在,我正在执行以下操作,它只是遍历对象数组列表并创建新的DateCount 对象,然后将这些对象添加到dateCounts 集合中。 DateCount 类有一个自定义的equals()hashCode() 方法,以确保dateCounts 集在任何给定日期只包含一个DateCount 实例。

data.stream()
        .forEach(obj -> {
            DateTime date = null;
            try {
                date = (sdf == null) ? new DateTime(obj[0]) : new DateTime(sdf.parse(obj[0].toString()));
                dateCounts.add(new DateCount(date.toDate(), (Long) obj[1]));
            } catch (ParseException e) {
                e.printStackTrace();
            }
        });

顺便说一句,我想知道是否还有一种方法可以避免在我的 lambda 表达式中执行 try/catch,只是为了将 String 解析为 Date

更新 -- 这是我目前为止的想法。尽管在 .map 调用中通过 List&lt;Object[]&gt; 流式传输似乎并不自然,但不确定是否有更好的方法。我介绍了我自己的Tuple&lt;X, Y&gt; 类,因为在没有访问器方法的情况下,在流中使用Object[] 并不能很好地工作。同样在最后两行中,我创建了一个TreeSet 和一个Comparator,以便我可以按日期对数据进行排序。我不觉得这是最好的方法,但我尝试调用 sorted() 并让 DateCount 实现 Comparable 似乎工作正常,但只要调用 collect(toSet()) 方法,排序就会消失.我认为这是流式呼叫的本质。我很好奇是否有办法在调用collect方法之前对其进行排序并在调用collect之后保留排序。

Set<DateCount> dateCounts = IntStream.range(0, DAYS_IN_WEEK)
        .mapToObj(idx -> new Tuple<>(new DateTime().withTimeAtStartOfDay().plusDays(idx).toDate(), 0L))
        .map(t -> {
            Tuple<String, Long> d = data.stream()
                    .map(arr -> new Tuple<>(arr[0].toString(), (Long) arr[1]))
                    .filter(tuple -> sdf.format(t.getX()).equals(tuple.getX()))
                    .findFirst().orElse(new Tuple<>(sdf.format(t.getX()), 0L));

            return new DateCount(DateTime.parse(d.getX(), DateTimeFormat.forPattern("yyyyMMdd")).toDate(), d.getY());
        })
        .collect(toSet());

TreeSet<DateCount> set = new TreeSet<>((a, b) -> a.compareTo(b));
set.addAll(dateCounts);

【问题讨论】:

    标签: java lambda java-8 java-stream


    【解决方案1】:

    您可以为收藏提供Supplier。直接替换

    .collect(toSet());
    

    .collect(toCollection(() -> new TreeSet<>((a, b) -> a.compareTo(b))));
    

    但请注意,为Comparator 指定(a, b) -&gt; a.compareTo(b) 意味着自然排序。如果您的元素实现了Comparable,则无需提供这样的比较器。你可以简单地使用

    .collect(toCollection(TreeSet::new));
    

    如果DateCount 具有compareTo 方法但未实现Comparator,您也可以指定DateCount::compareTo 而不是(a, b) -&gt; a.compareTo(b)


    请注意,在您的第一个mapToObj 操作中,没有必要将DateTime 包装在Tuple 中。您可以简单地映射到DateTime 并在下一个map 操作中使用该值(因为我在那里只看到t.getX(),第二个值0L 根本没有使用)。


    毕竟,我不确定你想要达到什么目的,但我有一种强烈的感觉,你可能会看看Collectors.groupingBy...

    【讨论】:

    • 谢谢,供应商方法看起来不错。我的主要不适是嵌套的数据流data.stream()。在我最初的mapToObj 中,您不需要映射到Tuple 似乎是对的。我将研究 groupingBy 方法。谢谢:)
    【解决方案2】:

    您可以将您的数据库数据映射到Map&lt;DateTime,Long&gt; 以便快速查找,因此您只需处理一次。然后,当您通过Set&lt;DateCount&gt; 进行流式传输时,您可以使用peek() 获取更新的值。这是一个例子。我使用Date 代替DateTime 只是为了更容易编写示例代码。

    Instant baseDate = Instant.now();
    Date date1 = new Date(baseDate.plus(1, ChronoUnit.DAYS).toEpochMilli());
    Date date2 = new Date(baseDate.plus(2, ChronoUnit.DAYS).toEpochMilli());
    Date date3 = new Date(baseDate.plus(3, ChronoUnit.DAYS).toEpochMilli());
    
    Set<DateCount> dateCounts = new TreeSet<DateCount>(); // Our mock Set
    dateCounts.add(new DateCount(date1, 0L));
    dateCounts.add(new DateCount(date2, 0L));
    dateCounts.add(new DateCount(date3, 0L));
    
    List<Object[]> data = new ArrayList<Object[]>(); // Our mock database Data      
    data.add(new Object[]{date1.toInstant().toEpochMilli(), 5L});
    data.add(new Object[]{date2.toInstant().toEpochMilli(), 3L});
    data.add(new Object[]{date3.toInstant().toEpochMilli(), 2L});
    
    //Map our data so we only have to process it once, and then we can look it up
    Map<Date,Long> mappedData = data.stream()
        .collect(Collectors.toConcurrentMap(k->new Date((long) k[0]), v->(Long)v[1]));
    
    //Update the data using peek as we stream through it
    dateCounts.stream()
        .peek(dc->dc.setCount(mappedData.get(dc.getDate())))
        .forEachOrdered(System.out::println);   
    

    运行时,输出如下,以便您可以看到 dateCounts 已更新:

    DateCount: Thu Dec 25 11:25:56 EST 2014 - 5
    DateCount: Fri Dec 26 11:25:56 EST 2014 - 3
    DateCount: Sat Dec 27 11:25:56 EST 2014 - 2
    

    这是我用来使上述代码工作的 DateCount 的实现......我想它与你的不太相似:

    public class DateCount implements Comparable<DateCount>{
        private Date date = null;
        private Long count = 0L;
    
        public DateCount(Date datetime, Long count){
            this.date = datetime;
            this.count = count;
        }
    
        public void setDateTime(Date date){
            this.date = date;
        }
    
        public Date getDate(){
            return date;
        }
    
        public void setCount(long count){
            this.count = count;
        }
    
        public long getCount(){
            return count;
        }
    
        @Override
        public int hashCode(){
            return date.hashCode() + 459;
        }
    
        @Override
        public boolean equals(Object o){
            boolean result = false;
            if (o instanceof DateCount){
                DateCount other = (DateCount) o;
                result = this.compareTo(other) == 0;
            }
            return result;
        }
    
        @Override
        public int compareTo(DateCount other) {
            if (this.date == null){
                return other.getDate() == null ? 0 : -1;
            } else {
                return date.compareTo(other.getDate());
            }
        }
    
        @Override
        public String toString(){
            return "DateCount: " + date.toString() + " - " + count;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-03-04
      • 2014-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-08
      • 2018-06-17
      • 2019-01-02
      相关资源
      最近更新 更多