如何在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;
}
}