如何在Java8中组合不同的流

如何在Java8中组合不同的流,java,lambda,java-8,java-stream,Java,Lambda,Java 8,Java Stream,我有一个集合,我使用以下代码创建它。这将创建一组7个初始计数为0的DateCount对象,从当前日期开始,每周每天一个 // 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 DateTim

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

// 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());
另一方面,我想知道是否还有一种方法可以避免在lambda表达式中进行try/catch操作,只用于将
字符串
解析为
日期

更新——这就是我到目前为止所想到的。但是,在.map调用中的
列表中进行流式处理似乎并不自然,不确定是否有更好的方法。我介绍了自己的
Tuple
类,因为在没有访问器方法的情况下,在流中使用
Object[]
效果不是很好。同样在最后两行中,我使用
比较器创建了一个
树集
,以便按日期对数据进行排序。我觉得这不是最好的方法,但我尝试调用
sorted()
并使
DateCount
实现
compariable
,这似乎很好,但只要调用
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);
Set dateCounts=IntStream.range(0,周内天数)
.mapToObj(idx->new Tuple(new DateTime().withTimeAtStartOfDay().plusDays(idx).toDate(),0L))
.map(t->{
Tuple d=data.stream()
.map(arr->new Tuple(arr[0].toString(),(Long)arr[1]))
.filter(tuple->sdf.format(t.getX()).equals(tuple.getX()))
.findFirst().orElse(新元组(sdf.format(t.getX()),0L));
返回新的DateCount(DateTime.parse(d.getX(),DateTimeFormat.forPattern(“yyyyMMdd”)).toDate(),d.getY());
})
.收集(toSet());
树集=新树集((a,b)->a.compareTo(b));
set.addAll(日期计数);

您可以为集合提供供应商。替换

.collect(toSet());

如果
DateCount
具有
compareTo
方法,但未实现
Comparator
,则还可以指定
DateCount::compareTo
,而不是
(a,b)->a.compareTo(b)


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



毕竟,我不确定您想要实现什么目标,但我有一种强烈的感觉,您可能需要查看一下……

您可以将数据库数据映射到
映射,以便快速查找,因此只需处理一次。然后,当您在
集合中流动时,您可以使用
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);   
这里是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;
    }
}
public类DateCount实现了可比较的{
私有日期=空;
专用长计数=0L;
公共日期计数(日期时间、长计数){
this.date=日期时间;
this.count=计数;
}
公共作废setDateTime(日期){
this.date=日期;
}
公共日期getDate(){
返回日期;
}
公共无效集合计数(长计数){
this.count=计数;
}
公共长getCount(){
返回计数;
}
@凌驾
公共int hashCode(){
返回日期。hashCode()+459;
}
@凌驾
公共布尔等于(对象o){
布尔结果=假;
if(o instanceof DateCount){
DateCount other=(DateCount)o;
结果=此。与(其他)相比=0;
}
返回结果;
}
@凌驾
公共整数比较(日期计数其他){
如果(this.date==null){
返回other.getDate()==null?0:-1;
}否则{
返回日期.compareTo(other.getDate());
}
}
@凌驾
公共字符串toString(){
返回“DateCount:”+date.toString()+“-”+count;
}
}

谢谢,供应商的方法看起来不错。我最不舒服的是嵌套的数据流
data.stream()
。在我的初始
mapToObj
中,不需要映射到
Tuple
,这似乎是对的。我将研究groupingBy方法。谢谢:)
.collect(toCollection(TreeSet::new));
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);   
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
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;
    }
}