Java 如何使用流api重写它

Java 如何使用流api重写它,java,java-stream,Java,Java Stream,我不知道流API的所有功能 我的任务是:我有一个带有URL的字符串列表,还有一个带有两个方法的自定义对象列表 String videoFromUrl(String url); boolean support(String url); 我应该从第一个列表中选择一个url,该url将由第二个列表的一个实例支持,然后返回转换后的url 我的代码是: @Override protected String videoSourceFromDocument(final Document docu

我不知道流API的所有功能

我的任务是:我有一个带有URL的字符串列表,还有一个带有两个方法的自定义对象列表

String videoFromUrl(String url);


boolean support(String url);
我应该从第一个列表中选择一个url,该url将由第二个列表的一个实例支持,然后返回转换后的url

我的代码是:

@Override
    protected String videoSourceFromDocument(final Document document) {
        final List<String> hrefs = ...;
        for (final String href : hrefs) {
            final Optional<VideoDownloader> videoDownloader = this.videoDownloaders/*this is my second list*/
                                                                  .stream()
                                                                  .filter(dwnldr->dwnldr.support(href))
                                                                  .findFirst();
            if(videoDownloader.isPresent()){
                return videoDownloader.get().videoFromUrl(href);
            }
        }
        this.logger().warn("Url {} doesn't has video source",document.baseUri());
        throw new IllegalArgumentException();
    }
@覆盖
受保护的字符串videoSourceFromDocument(最终文档){
最终列表hrefs=。。。;
for(最终字符串href:hrefs){
最终可选videoDownloader=this.videoDownloaders/*这是我的第二个列表*/
.stream()
.filter(dwnldr->dwnldr.support(href))
.findFirst();
if(videoDownloader.isPresent()){
返回videoDownloader.get().videoFromUrl(href);
}
}
this.logger().warn(“Url{}没有视频源”,document.baseUri());
抛出新的IllegalArgumentException();
}

使用流API重写它是更好的方法吗?

当您需要两个内部循环以强制方式执行某些操作时,使用流执行相同操作的解决方案通常是使用flatMap:

protected String videoSourceFromDocument(final Document document) {
    final List<String> hrefs = ...;
    return hrefs.stream()
                .flatMap(href -> this.videoDownloaders.stream()
                                     .filter(d -> d.support(href))
                                     .map(d -> d.videoFromUrl(href)))
                .findFirst()
                .orElseThrow(() -> {
                    this.logger().warn("Url {} doesn't has video source", document.baseUri());
                    return new IllegalArgumentException();
                });
}
受保护的字符串videoSourceFromDocument(最终文档){
最终列表hrefs=。。。;
返回hrefs.stream()
.flatMap(href->this.videoDownloaders.stream()
.filter(d->d.support(href))
.map(d->d.videoFromUrl(href)))
.findFirst()
.orElseThrow(()->{
this.logger().warn(“Url{}没有视频源”,document.baseUri());
返回新的IllegalArgumentException();
});
}

不过,我会删除日志,并将信息性消息放在IllegalArgumentException中。或者只需返回一个
可选的
,以便调用者可以决定在没有视频源时做什么。

您可以使用一些
可选的
方法将for循环替换为流管道:

return hrefs.stream() // Stream<String>
            .map(href -> this.videoDownloaders
                             .stream() // Stream<VideoDownloader>
                             .filter(dwnldr->dwnldr.support(href))
                             .findFirst() // Optional<VideoDownloader>
                             .map(dwnldr -> dwnldr.videoFromUrl(href))) // Stream<Optional<String>>
            .filter(Optional::isPresent) // keep only the non-empty Optionals
            .findFirst() // Optional<Optional<String>>
            .orElseThrow(IllegalArgumentException::new) // Optional<String>
            .get(); // String
返回hrefs.stream()//stream
.map(href->this.videoDownloaders
.stream()//流
.filter(dwnldr->dwnldr.support(href))
.findFirst()//可选
.map(dwnldr->dwnldr.videoFromUrl(href))//流
.filter(可选::isPresent)//仅保留非空选项
.findFirst()//可选
.orelsetrow(IllegalArgumentException::new)//可选
.get();//一串

您是在返回任何支持它的
videoDownloader
转换的
videoFromUrl
的结果吗?我不明白您的问题。您已经在使用streams。您想摆脱第一个增强的for循环吗?我的代码工作正常,但可能Stream api中有一些方法应该使用,而不是仅仅指出日志记录然后抛出无消息异常不是很有用:最好将消息输出到异常中,这样您就可以了解原因。但是也不要记录:抛出或记录,不要两者都做。但是抛出
IllegalArgumentException
是否合适呢?这是一个未检查的异常,应该用来指示编程错误:如果不调用此方法,您怎么知道不应该为给定文档调用此方法?你必须把逻辑复制到别处。最好让此方法返回一个
可选的
videoDownloader.map(v->v.videoFromUrl(href))的结果)
:然后您可以指示文档是否有视频下载器,如果有,还可以使用一个简单的API来获取它。意思是
.map(d->d.videoFromUrl(href)))
?您是否需要
.filter(可选::isPresent)
,并且此文件不会返回
可选的
@user7谢谢您的评论。我需要
.filter(可选::isPresent)
,因为我的
映射
将原始
转换为
,我想找到该流的非空元素。但是,我必须在末尾添加另一个
get()
。我添加了管道中每个步骤的类型,以澄清问题。感谢您对其进行了修复。调用
get
使我想到它是否会抛出
NoTouchElementException
@user7,这要感谢
.filter(可选::isPresent)