【发布时间】:2015-12-15 21:22:17
【问题描述】:
考虑以下类:
public class Order {
private String id;
private List<Order> orders = new ArrayList<>();
@Override
public String toString() {
return this.id;
}
// getters & setters
}
注意:请务必注意,我无法修改此类,因为我从外部 API 使用它。
还要考虑以下订单层次结构:
Order o1 = new Order();
o1.setId("1");
Order o11 = new Order();
o11.setId("1.1");
Order o111 = new Order();
o111.setId("1.1.1");
List<Order> o11Children = new ArrayList<>(Arrays.asList(o111));
o11.setOrders(o11Children);
Order o12 = new Order();
o12.setId("1.2");
List<Order> o1Children = new ArrayList<>(Arrays.asList(o11, o12));
o1.setOrders(o1Children);
Order o2 = new Order();
o2.setId("2");
Order o21 = new Order();
o21.setId("2.1");
Order o22 = new Order();
o22.setId("2.2");
Order o23 = new Order();
o23.setId("2.3");
List<Order> o2Children = new ArrayList<>(Arrays.asList(o21, o22, o23));
o2.setOrders(o2Children);
List<Order> orders = new ArrayList<>(Arrays.asList(o1, o2));
可以用这种方式直观地表示:
1
1.1
1.1.1
1.2
2
2.1
2.2
2.3
现在,我想将这个订单层次结构扁平化为List,以便得到以下信息:
[1, 1.1, 1.1.1, 1.2, 2, 2.1, 2.2, 2.3]
我已经通过递归地使用flatMap()(以及一个辅助类)来做到这一点,如下所示:
List<Order> flattened = orders.stream()
.flatMap(Helper::flatten)
.collect(Collectors.toList());
这是辅助类:
public final class Helper {
private Helper() {
}
public static Stream<Order> flatten(Order order) {
return Stream.concat(
Stream.of(order),
order.getOrders().stream().flatMap(Helper::flatten)); // recursion here
}
}
下面一行:
System.out.println(flattened);
产生以下输出:
[1, 1.1, 1.1.1, 1.2, 2, 2.1, 2.2, 2.3]
到目前为止一切顺利。结果绝对正确。
但是,after reading this question,我对在递归方法中使用 flatMap() 有一些顾虑。特别是,我想知道流是如何扩展的(如果这是术语)。所以我修改了Helper类并使用peek(System.out::println)来检查这个:
public static final class Helper {
private Helper() {
}
public static Stream<Order> flatten(Order order) {
return Stream.concat(
Stream.of(order),
order.getOrders().stream().flatMap(Helper::flatten))
.peek(System.out::println);
}
}
输出是:
1
1.1
1.1
1.1.1
1.1.1
1.1.1
1.2
1.2
2
2.1
2.1
2.2
2.2
2.3
2.3
我不确定这是否是应该打印的输出。
所以,我想知道是否可以让中间流包含重复的元素。此外,这种方法的优缺点是什么?毕竟,以这种方式使用flatMap() 是否正确?有没有更好的方法来达到同样的效果?
【问题讨论】:
-
只是好奇:为什么在创建订单后设置 id 而不是将其作为构造函数的参数?
-
@sprinter 我无法修改
Order类,因为它是我正在使用的 API 的一部分。 -
啊,我明白了。然后我的大部分答案都毫无用处。可能值得将这条信息添加到您的问题中。
-
@sprinter 我会编辑它,谢谢。
标签: java java-8 java-stream