[英]How can I accomplish using Optional and Streams?
public class Product {
private String name;
private List<Image> images;
//getters and setters
public class Images {
private String url;
private List<Thumbnail> thumbnails;
// getters and setters
public class Thumbnail{
//getters and setters
private String url;
}
}
}
}
I have this class. 我有这门课。 I need to fetch product name, url of the first image and url of the first thumbnail.
我需要获取第一个图像的产品名称,网址和第一个缩略图的网址。 I also need to make sure product, images and thumbnails are non-empty.
我还需要确保产品,图像和缩略图都是非空的。
This is how I am trying to do it: 这就是我试图这样做的方式:
Optional.ofNullable(product).ifPresent(productData -> {
response.setProductName(productData.getName());
Optional.ofNullable(productData.getImages()).ifPresent(images -> {
images.stream().findFirst().ifPresent(image -> {
response.setImageUrl(image.getUrl());
Optional.ofNullable(image.getThumbnails()).ifPresent(thumbnails -> {
thumbnails.stream().findFirst().ifPresent(thumbnail -> {
response.getThumbnailUrl();
});
});
});
});
});
Is there a better way? 有没有更好的办法?
You shouldn't ever have null
lists. 你不应该
null
列表。 An empty list represents the same thing without having to introduce a null check. 空列表表示相同的事情,而不必引入空检查。 That lets you get rid of two
ifPresent
checks. 这可以让你摆脱两个
ifPresent
检查。
Optional.ofNullable(product).ifPresent(productData -> {
response.setProductName(productData.getName());
productData.getImages().stream().findFirst().ifPresent(image -> {
response.setImageUrl(image.getUrl());
image.getThumbnails().stream().findFirst().ifPresent(thumbnail -> {
response.getThumbnailUrl();
});
});
});
Optionals and streams aren't really doing you any favors. 可选项和流并没有真正为您带来任何好处。 Don't use them just because they exist.
不要仅因为存在而使用它们。 Consider just using regular
if
statements. 考虑使用常规
if
语句。
if (product == null) {
return;
}
if (!product.getImages().isEmpty()) {
Image image = product.getImages().get(0);
response.setImageUrl(image.getUrl());
if (!image.getThumbnails().isEmpty()) {
response.getThumbnailUrl();
}
}
Alternatively, you could simulate stream().findFirst().ifPresent()
with for
loops that break after the first iteration. 或者,您可以模拟
stream().findFirst().ifPresent()
其中for
循环在第一次迭代后中断。
if (product == null) {
return;
}
for (Image image: product.getImages()) {
response.setImageUrl(image.getUrl());
for (Thumbnail thumbnail: image.getThumbnails()) {
response.getThumbnailUrl();
break;
}
break;
}
@John's answer is the correct one. @ John的回答是正确的。 If you can, return empty lists.
如果可以,请返回空列表。
It might also be that you want to distinguish between not having any items and not having a result (in your case it doesn't make much sense, but we're talking hypothetically). 也许你想要区分没有任何项目而没有结果(在你的情况下它没有多大意义,但我们假设是在讨论)。 Then return
Optional<List<T>>
instead of returning null
then converting it. 然后返回
Optional<List<T>>
而不是返回null
然后转换它。 Then @Johannes' answer is the correct one. 然后@Johannes的回答是正确的。
Another way of thinking about the problem is, if you have no control over the return values, to convert it to a stream to chain the calls: 另一种思考问题的方法是,如果您无法控制返回值,则将其转换为流以链接调用:
Optional.ofNullable(possiblyNullProduct).stream()
.peek(product -> response.setProductName(product.getName()))
.map(Product::getImages)
.filter(Objects::nonNull)
.map(images -> images.stream().findFirst())
.filter(Optional::isPresent).map(Optional::get)
.peek(image -> response.setImageUrl(image.getUrl())
.map(Image::getThumbnails)
.filter(Objects::nonNull)
.map(thumbnails -> thumbnails.stream().findFirst())
.filter(Optional::isPresent).map(Optional::get)
.forEach(thumbnail -> response.getThumbnailUrl());
Optional::stream
was added in Java 9 . 在Java 9中添加了
Optional::stream
。
This is just another solution, by no means a better solution. 这只是另一种解决方案,绝不是更好的解决方案。 I would welcome any comments on the performance.
我欢迎任何关于表现的评论。
Another option to get the first item of each list is to convert to an Optional and back into a Stream: 获取每个列表的第一项的另一个选项是转换为Optional并返回Stream:
.map(Product::getImages)
.filter(Objects::nonNull)
.flatMap(List::stream).findFirst().stream() // <- changed here
.peek(image -> ...)
And you can also change out the last three lines in a similar way: 你也可以用类似的方式改变最后三行:
.map(Image::getThumbnails)
.filter(Objects::nonNull)
.flatMap(List::stream).findFirst() // <- from here
.ifPresent(thumbnail -> response.getThumbnailUrl());
Yes, flatMap
will help here: 是的,
flatMap
将在这里提供帮助:
Optional<Product> optProduct = Optional.ofNullable(product);
optProduct.ifPresent(p -> response.setProductName(p.getName()));
Optional<Image> optImage = optProduct.flatMap(p -> Optional.ofNullable(p.getImages()))
.stream().flatMap(il -> il.stream()).findFirst();
optImage.ifPresent(i -> response.setImageUrl(i.getUrl()));
optImage.flatMap(i -> Optional.ofNullable(i.getThumbnails()))
.stream().flatMap(tl -> tl.stream()).findFirst()
.ifPresent(t -> response.getThumbnailUrl()); // WTF?
Node that Optional.stream()
was added in Java 9. 在Java 9中添加了
Optional.stream()
节点。
I don't think the Optionals are helping much here. 我不认为Optionals在这方面有很多帮助。 I would clean up the code by abstracting the iteration logic, like this:
我会通过抽象迭代逻辑来清理代码,如下所示:
private <T> void findFirst(List<T> list, Consumer<T> action) {
if (list != null) {
list.stream()
.findFirst()
.ifPresent(action);
}
}
if (product != null) {
response.setProductName(productData.getName());
findFirst(productData.getImages(), image -> {
response.setImageUrl(image.getUrl());
findFirst(image.getThumbnails(), thumbnail -> response.setThumbnailUrl(thumbnail.getUrl()));
});
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.