当您拥有对象流时,您可以非常优雅地过滤它们。
\nswimmingAnimalStream = animalStream\n .filter(Animal::canSwim);\nRun Code Online (Sandbox Code Playgroud)\n当您有稍微复杂的过滤器而不是使用方法引用时,您必须使用 Lambda。
\ngreenAnimals = animalStream\n .filter(animal -> animal.getColor().equals(Colors.GREEN));\nRun Code Online (Sandbox Code Playgroud)\n有没有办法在过滤之前映射值,但在过滤之后仍然拥有完整的对象?\n所以下面的不是我想要的:
\nanimalStream\n .map(Animal::getColor)\n .filter(Colors.GREEN::equals)\nRun Code Online (Sandbox Code Playgroud)\n这样我就只剩下颜色信息了。\n我还想避免的是提取方法。我正在寻找一种更简化的方法来做到这一点。例如这样的事情:
\nanimalStream\n .filter(Colors.GREEN::equals, Animal::getColor);\nRun Code Online (Sandbox Code Playgroud)\n该过滤器方法的方法签名如下所示。
\n<MAPPED> Stream<T> filter(Predicate<MAPPED> filter, Function<? super T, MAPPED> mappingFunction);\nRun Code Online (Sandbox Code Playgroud)\n更好的是您可以加入多个映射功能的版本。在运行过程中,人们可以使用可变参数来表示映射函数。但老实说,我不知道\xe2\x80\x99 不知道泛型如何实现这一点。但\xe2\x80\x99 是一个不同的故事。
\n该解决方案还应该能够使用人们可以想象的任何谓词。等于只是一个例子。另一个示例是检查对象中的字段是否存在。
\nanimalWithMotherStream = animalStream\n .filter(Optional::isPresent, Animal::getMother);\nRun Code Online (Sandbox Code Playgroud)\n现在有人有更干净的解决方案,或者已经有这样做的库吗?
\n假设我们有一个动物流。
我们有不同的动物子类,并且我们希望在流上应用过滤器以仅包含流中的斑马。我们现在仍然有动物流,但只包含斑马。为了获得斑马流,我们仍然需要进行投射。
Stream<Zebra> zebraStream = animalStream
.filter(Zebra.class::isInstance)
.map(Zebra.class::cast);
Run Code Online (Sandbox Code Playgroud)
Java 14 引入了instanceof 的模式匹配,所以我们现在可以使用:
if (animal instanceof Zebra zebra) {
System.out.println(zebra.countStripes());
}
Run Code Online (Sandbox Code Playgroud)
有没有办法在流管道中使用模式匹配?当然你可以这样做:
Stream<Zebra> zebraStream = animalStream.map(animal -> {
if (animal instanceof Zebra zebra) {
return zebra;
}
return null;
})
.filter(Objects::nonNull);
Run Code Online (Sandbox Code Playgroud)
但恕我直言,这真的很难看。
假设我有一个Optional包含Stream:
Optional<Stream<Integer>> optionalStream = Optional.of(Stream.of(1, 2, 3));
Run Code Online (Sandbox Code Playgroud)
现在我需要提取它Stream本身。如果Optional为空,您想要获得一个空的 Stream。
我正在寻找类似的东西,flatStream()可以一步执行转换。我怎样才能做到这一点?
我目前的尝试:
Stream<Integer> stream = optionalStream.stream().flatMap(Function.identity());
Run Code Online (Sandbox Code Playgroud)
在我的真实场景中,我有这样的东西,它给了我一个Stream<Optional<Foo>>:
stream.findFirst().map(e -> e.getChildren())
Run Code Online (Sandbox Code Playgroud) 假设您有一个Optional,并且您想要多次使用该Optional。\n您现在可以将该Optional保存到一个变量中;然后使用ifPresent两次:
Optional<Animal> optionalAnimal = animalService.getAllAnimals().findFirst();\noptionalAnimal.ifPresent(Animal::eat);\noptionalAnimal.ifPresent(Animal::drink);\nRun Code Online (Sandbox Code Playgroud)\n另一种解决方案是放弃方法引用并使用同时执行这两项操作的 lambda:
\nanimalService.getAllAnimals().findFirst()\n .ifPresent(animal -> {\n animal.drink();\n animal.eat();\n });\nRun Code Online (Sandbox Code Playgroud)\n如果我可以控制可选中使用的类,我可以简单地更改方法以使用类似工厂的模式。这样它animal.drink()就会自行返回。\n然后我可以写:
animalService.getAllAnimals().findFirst()\n .map(Animal::drink)\n .ifPresent(Animal::eat);\nRun Code Online (Sandbox Code Playgroud)\n但这在语义上会很奇怪。而且我不\xe2\x80\x99t 总是可以控制我在可选中使用的每个类。有些类是最终的,所以我什至无法将它们扩展为具有工厂样式的方法。
\n此外,Optional 类也是final 类,因此扩展Optional 本身也不是选择。\n所有这些对我来说毫无意义。ifPresent()返回无效。如果ifPresent()返回可选本身(类似于peek()流),它将更接近我的目标。
还有其他我没有想到的解决方案吗?
\n我想要的是这样的:
\nanimalService.getAllAnimals().findFirst()\n .ifPresent(Animal::drink)\n .ifPresent(Animal::eat);\nRun Code Online (Sandbox Code Playgroud)\n