Java 8复杂的自定义收集器

我有一个对象流,我想以下面的方式收集。

假设我们正在处理论坛post:

class Post { private Date time; private Data data } 

我想创建一个按期间对post进行分组的列表。 如果X分钟没有post,请创建新组。

 class PostsGroup{ List posts = new ArrayList (); } 

我想获得一个List其中包含按时间间隔分组的post。

例如:间隔10分钟。

post:

 [{time:x, data:{}}, {time:x + 3, data:{}} , {time:x+ 12, data:{}, {time:x + 45, data:{}}}] 

我想获得一个post组列表:

 [ {posts : [{time:x, data:{}}, {time:x + 3, data:{}}, {time:x+ 12, data:{}]]}, {posts : [{time:x+ 45, data:{}]} ] 
  • 注意第一组持续到X + 22.然后在X + 45收到一个新的post。

这可能吗?

使用我的StreamEx库的groupRuns方法可以轻松解决此问题:

 long MAX_INTERVAL = TimeUnit.MINUTES.toMillis(10); StreamEx.of(posts) .groupRuns((p1, p2) -> p2.time.getTime() - p1.time.getTime() <= MAX_INTERVAL) .map(PostsGroup::new) .toList(); 

我假设你有一个构造函数

 class PostsGroup { private List posts; public PostsGroup(List posts) { this.posts = posts; } } 

StreamEx.groupRuns方法采用BiPredicate ,该StreamEx.groupRuns应用于两个相邻的输入元素,如果必须将它们组合在一起,则返回true。 此方法创建列表流,其中每个列表代表该组。 这种方法很懒惰,可以在并行流中正常工作。

您需要在流条目之间保留状态并为自己编写分组分类器。 这样的事情将是一个良好的开端。

 class Post { private final long time; private final String data; public Post(long time, String data) { this.time = time; this.data = data; } @Override public String toString() { return "Post{" + "time=" + time + ", data=" + data + '}'; } } public void test() { System.out.println("Hello"); long t = 0; List posts = Arrays.asList( new Post(t, "One"), new Post(t + 1000, "Two"), new Post(t + 10000, "Three") ); // Group every 5 seconds. Map> gouped = posts .stream() .collect(Collectors.groupingBy(new ClassifyByTimeBetween(5000))); gouped.entrySet().stream().forEach((e) -> { System.out.println(e.getKey() + " -> " + e.getValue()); }); } class ClassifyByTimeBetween implements Function { final long delay; long currentGroupBy = -1; long lastDateSeen = -1; public ClassifyByTimeBetween(long delay) { this.delay = delay; } @Override public Long apply(Post p) { if (lastDateSeen >= 0) { if (p.time > lastDateSeen + delay) { // Grab this one. currentGroupBy = p.time; } } else { // First time - start there. currentGroupBy = p.time; } lastDateSeen = p.time; return currentGroupBy; } }