Thr*_*ion 0 java java-8 java-stream collectors
我有一个 Foo 列表,在每个 Foo 上,我应用了一个处理器方法来获取ValidItem.
如果处理中出现错误,那么我返回ErrorItem.
现在如何通过 Java 8 流处理它以得到 2 个不同列表形式的结果
List<Foo> FooList = someList....;
class ValidItem extend Item{......}
class ErrorItem extend Item{......}
Item processItem(Foo foo){
return either an object of ValidItem or ErrorItem;
}
Run Code Online (Sandbox Code Playgroud)
我相信我能做到
Map<Class,List<Item>> itemsMap =
FooList
.stream()
.map(processItem)
.collect(Collectors.groupingBy(Object::getClass));
Run Code Online (Sandbox Code Playgroud)
但作为List<Parent>不是一个List<Child>让我无法强制转换地图结果变成List<ValidItem>
现实ErrorItem,并ValidItem在所有,没有关系只是为这种蒸汽处理和processItem方法我着想两个完全不同的类让他们在同一层次通过扩展标记项目班级,。
在代码中的许多其他地方,我不能/不应该将 ValidItem 称为 Item ,因为它给出了它也可以是 ErroItem 的想法。
是否有使用流的正确方法,最后我得到 2 个列表。和 ErrorItem 和 ValidItem 没有扩展相同的 Item 类?
############## 更新##############
正如我所说的 ValidItem 和 ErrorItem 不应该相同,所以我改变了 process 方法的签名和通过它一个列表。我知道这不是使用 Stream 的方式。如果你有更好的方法,请告诉我
List<Foo> FooList = someList....;
class ValidItem {......}
class InvalidFoo{......}
ValidItem processFoo(Foo foo, List<InvalidFoo> foolist){
Do some processing on foo.
either return new ValidItem ();
OR
fooList.add(new InvalidFoo()) , and then return null;
}
List<InvalidFoo> invalidFooList = new ArrayList();
List<ValidItem> validItem =
fooList
.stream()
.map(e->processItem(e,invalidFooList))
.filter(Objects::notNull)
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
现在我有无效和有效列表,但这看起来不像一个干净的流代码。
使用最新的 Java 版本,您可以使用
对于Item processItem(Foo foo)返回ValidItem或的方法ErrorItem:
Map.Entry<List<ValidItem>, List<ErrorItem>> collected = fooList.stream()
.map(this::processItem)
.collect(teeing(
flatMapping(x -> x instanceof ValidItem? Stream.of((ValidItem)x):null, toList()),
flatMapping(x -> x instanceof ErrorItem? Stream.of((ErrorItem)x):null, toList()),
AbstractMap.SimpleImmutableEntry::new
));
List<ValidItem> valid = collected.getKey();
List<ErrorItem> invalid = collected.getValue();
Run Code Online (Sandbox Code Playgroud)对于ValidItem processFoo(Foo foo, List<InvalidFoo> foolist):
Map.Entry<List<ValidItem>, List<InvalidFoo>> collected = fooList.stream()
.map(foo -> {
List<InvalidFoo> invalid = new ArrayList<>(1);
ValidItem vi = processFoo(foo, invalid);
return new AbstractMap.SimpleImmutableEntry<>(
vi == null? Collections.<ValidItem>emptyList():
Collections.singletonList(vi),
invalid);
})
.collect(teeing(
flatMapping(e -> e.getKey().stream(), toList()),
flatMapping(e -> e.getValue().stream(), toList()),
AbstractMap.SimpleImmutableEntry::new
));
List<ValidItem> valid = collected.getKey();
List<InvalidFoo> invalid = collected.getValue();
Run Code Online (Sandbox Code Playgroud)该flatMapping收集器在Java中9引入了
在这种特殊情况下,而不是
flatMapping(x -> x instanceof ValidItem? Stream.of((ValidItem)x): null, toList())
Run Code Online (Sandbox Code Playgroud)
你也可以使用
filtering(x -> x instanceof ValidItem, mapping(x -> (ValidItem)x, toList()))
Run Code Online (Sandbox Code Playgroud)
但是每个变体都需要 Java 9,filteringJava 8 中也不存在。teeing收集器甚至需要 Java 12。
然而,这些收集器并不难实现。
这个答案最后包含一个 Java 8 兼容版本的flatMapping收集器。如果你想使用了替代的filtering和mapping,你可以找到一个Java 8兼容的版本filtering中这个答案。最后,这个答案包含一个 Java 8 兼容的teeing收集器变体。
当您将这些收集器添加到您的代码库时,本答案开头的解决方案可在 Java 8 下运行,并且很容易适应未来的版本。假设import static java.util.stream.Collectors.*;在你的源文件中,你只需要删除这些方法的反向移植,就可以切换到标准的 JDK 版本。
如果processItem返回一个EitherorPair类型而不是上面提到的两个变体会更好。如果您不想使用 3rd 方库,您可以使用Map.Entry实例作为“穷人的配对类型”。
有一个方法签名像
/** Returns an entry with either, key or value, being {@code null} */
Map.Entry<ValidItem,InvalidFoo> processItem(Foo foo){
Run Code Online (Sandbox Code Playgroud)
这可以通过返回一个实例来实现AbstractMap.SimpleImmutableEntry,
JDK 9+ 解决方案可能看起来像
Map.Entry<List<ValidItem>, List<InvalidFoo>> collected = fooList.stream()
.map(this::processItem)
.collect(teeing(
flatMapping(e -> Stream.ofNullable(e.getKey()), toList()),
flatMapping(e -> Stream.ofNullable(e.getValue()), toList()),
AbstractMap.SimpleImmutableEntry::new
));
Run Code Online (Sandbox Code Playgroud)
和 Java 8 兼容(使用链接的收集器反向移植时)版本:
Map.Entry<List<ValidItem>, List<InvalidFoo>> collected = fooList.stream()
.map(this::processItem)
.collect(teeing(
flatMapping(e -> Stream.of(e.getKey()).filter(Objects::nonNull), toList()),
flatMapping(e -> Stream.of(e.getValue()).filter(Objects::nonNull), toList()),
AbstractMap.SimpleImmutableEntry::new
));
Run Code Online (Sandbox Code Playgroud)
或者
Map.Entry<List<ValidItem>, List<InvalidFoo>> collected = fooList.stream()
.map(this::processItem)
.collect(teeing(
mapping(Map.Entry::getKey, filtering(Objects::nonNull, toList())),
mapping(Map.Entry::getValue, filtering(Objects::nonNull, toList())),
AbstractMap.SimpleImmutableEntry::new
));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
446 次 |
| 最近记录: |