Java 8 流或迭代器哪个更好
我在玩Java*Stream API,在Lagecy系统中有以下代码:Java 8 流或迭代器哪个更好,java-8,Java 8,我在玩Java*Stream API,在Lagecy系统中有以下代码: Iterator itr = configMap.entrySet().iterator(); List<String> resultList = new ArrayList<String>(); while(itr.hasNext()){ Entry e = (Entry)itr.next(); Config rc =
Iterator itr = configMap.entrySet().iterator();
List<String> resultList = new ArrayList<String>();
while(itr.hasNext()){
Entry e = (Entry)itr.next();
Config rc = (Config)e.getValue();
if (rc != null && rc.getVisibleTo() != null && (rc.getVisibleTo().equalsIgnoreCase("0010") || rc.getVisibleTo().equalsIgnoreCase("0111") || rc.getVisibleTo().equalsIgnoreCase("0011"))){
resultList .add(rc.getName());
}
}
Iterator itr=configMap.entrySet().Iterator();
List resultList=new ArrayList();
while(itr.hasNext()){
条目e=(条目)itr.next();
Config rc=(Config)e.getValue();
如果(rc!=null&&rc.getVisibleTo()!=null&(rc.getVisibleTo().equalsIgnoreCase(“0010”)| | rc.getVisibleTo().equalsIgnoreCase(“0111”)| rc.getVisibleTo().equalsIgnoreCase(“0011”){
add(rc.getName());
}
}
我编写了与上述代码等价的流,如下所示:
List<String> resultList = configMap.entrySet()
.parallelStream()
.map(r -> r.getValue())
.filter(r -> r.getVisibleTo() != null)
.filter(r -> {return
r.getVisibleTo().equalsIgnoreCase("0010")
|| r.getVisibleTo().equalsIgnoreCase("0111")
|| r.getVisibleTo().equalsIgnoreCase("0011");
})
.map(r -> r.getName())
.collect(Collectors.toList());
List resultList=configMap.entrySet()
.parallelStream()
.map(r->r.getValue())
.filter(r->r.getVisibleTo()!=null)
.filter(r->{return
r、 getVisibleTo().equalsIgnoreCase(“0010”)
||r.getVisibleTo().equalsIgnoreCase(“0111”)
||r.getVisibleTo().equalsIgnoreCase(“0011”);
})
.map(r->r.getName())
.collect(Collectors.toList());
这两种方法都能让我得到想要的结果。我的问题是,在这种情况下,哪种性能方面的写作方式更好?如果我选择其中一个而不是另一个,我是否真的获得了任何价值?地图中大约有1000个值。首先,如果性能是您关心的问题,那么您应该根据事实来决定,所以请测量,不要猜测(即使用) 对于简单的情况,迭代或经典循环往往比流更快。另一方面,流可以更快,并且通常可以通过并行性(工作负载很容易并行化)进一步加速。在大多数情况下,这并不重要(以我的经验),因为数据集太小和/或使用它的代码没有足够的性能标准
关于可读性/可维护性,我倾向于使用流/函数方法来更好地分离关注点。但是,for-each循环也可能会改进迭代代码。因此,没有简单的是/否答案,这完全取决于上下文。首先,如果性能是您关心的问题,您应该根据事实做出决定,所以要衡量,而不是猜测(即使用) 对于简单的情况,迭代或经典循环往往比流更快。另一方面,流可以更快,并且通常可以通过并行性(工作负载很容易并行化)进一步加速。在大多数情况下,这并不重要(以我的经验),因为数据集太小和/或使用它的代码没有足够的性能标准
关于可读性/可维护性,我倾向于使用流/函数方法来更好地分离关注点。但是,for-each循环也可能会改进迭代代码。因此,没有简单的“是/否”答案,这完全取决于上下文。因为您将此作为并行流编写,尝试多线程并划分工作,您可能会看到管理线程的开销导致性能下降,因为您的作业有点小。这里的另一个陷阱是,由于您使用的是
CommonForkJoinPool
(默认的线程池),因此这不是一个很好的选择,因为用任务阻塞线程池会降低整个应用程序的性能(虽然这与您的工作规模不大相关,但需要记住)
也就是说,如果您使用单线程
configMap.entrySet().stream()
,那么性能差异可能会稍微慢一点,但可读性远远弥补了这一点。因此,选择是在代码速度稍快还是可读性更好之间做出决定,这完全取决于您(但我个人会选择流)。由于您将此作为并行流编写,试图多线程并分配工作,因此您可能会看到管理线程的开销会导致性能下降,考虑到你的工作有点小。这里的另一个陷阱是,由于您使用的是CommonForkJoinPool
(默认的线程池),因此这不是一个很好的选择,因为用任务阻塞线程池会降低整个应用程序的性能(虽然这与您的工作规模不大相关,但需要记住)
也就是说,如果您使用单线程
configMap.entrySet().stream()
,那么性能差异可能会稍微慢一点,但可读性远远弥补了这一点。因此,选择是在稍微快一点的代码还是更好的可读性之间做出决定,这完全取决于您(但我会亲自选择流)。我只需要稍微重写sream
示例:
List<String> resultList = configMap.entrySet()
.parallelStream()
.map(Map.Entry::getValue)
.filter(Objects::nonNull) // value might be a null
.filter(r ->
((Predicate<String>) "0010"::equals)
.or("0111"::equals) // null-save equivalent to "0111".equals(value)
.or("0011"::equals)
.test(r.getVisibleTo())
)
.map(Config::getName)
.collect(Collectors.toList());
我只想稍微重写一下
sream
示例:
List<String> resultList = configMap.entrySet()
.parallelStream()
.map(Map.Entry::getValue)
.filter(Objects::nonNull) // value might be a null
.filter(r ->
((Predicate<String>) "0010"::equals)
.or("0111"::equals) // null-save equivalent to "0111".equals(value)
.or("0011"::equals)
.test(r.getVisibleTo())
)
.map(Config::getName)
.collect(Collectors.toList());
这看起来像是基于意见的问题。有人会说a是好的。有人会说b是好的。它可能会在人与人之间产生争论,并影响此网站。这也可能会让你投反对票(不是我)。因此,请尝试编辑您的问题。为了可读性,我将从.filter(r->r.getVisibleTo()!=null)filter(r->{return r.getVisibleTo().equalsIgnoreCase(“0010”)| | r.getVisibleTo().equalsIgnoreCase(“0111”)创建一个单独的谓词| | r.getVisibleTo().equalsIgnoreCase(“0011”)})我会选择更具可读性的方法(即流方法),我非常喜欢使用
equalsIgnoreCase
。你永远不知道,也许有小写的0
s或大写的1
s……你最好专注于编写清晰、明显且可维护的代码,而不是关注微观性能问题。在茫茫人海中