我有以下代码:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="app" ng-controller="myCtrl">
<select map-value name="traveller_type" class="full-width" ng-model="traveller_type" ng-options="
item as item.value for item in personalityFields.traveller_type track by item.value">
<option value="" disabled selected> Choose ...</option>
</select>
{{traveller_type}}
</div>
如您所见,我将相同的列表流式传输3次,因为我想找到3个不同的值。如果我在For-Each循环中执行此操作,我只能循环一次。
这是一个更好的,性能明智的做一个for循环然后,所以我只循环一次?我发现这些流更具可读性。
编辑:我进行了一些测试:
mostRecentMessageSentDate = messageInfoList
.stream()
.findFirst().orElse(new MessageInfo())
.getSentDate();
unprocessedMessagesCount = messageInfoList
.stream()
.filter(messageInfo -> messageInfo.getProcessedDate() == null)
.count();
hasAttachment = messageInfoList
.stream()
.anyMatch(messageInfo -> messageInfo.getAttachmentCount() > 0);
并且正如预期的那样,for循环总是比流
更快import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
List<Integer> integerList = populateList();
System.out.println("Stream time: " + timeStream(integerList));
System.out.println("Loop time: " + timeLoop(integerList));
}
private static List<Integer> populateList() {
return IntStream.range(0, 10000000)
.boxed()
.collect(Collectors.toList());
}
private static long timeStream(List<Integer> integerList) {
long start = System.currentTimeMillis();
Integer first = integerList
.stream()
.findFirst().orElse(0);
long containsNumbersGreaterThan10000 = integerList
.stream()
.filter(i -> i > 10000)
.count();
boolean has10000 = integerList
.stream()
.anyMatch(i -> i == 10000);
long end = System.currentTimeMillis();
System.out.println("first: " + first);
System.out.println("containsNumbersGreaterThan10000: " + containsNumbersGreaterThan10000);
System.out.println("has10000: " + has10000);
return end - start;
}
private static long timeLoop(List<Integer> integerList) {
long start = System.currentTimeMillis();
Integer first = 0;
boolean has10000 = false;
int count = 0;
long containsNumbersGreaterThan10000 = 0L;
for (Integer i : integerList) {
if (count == 0) {
first = i;
}
if (i > 10000) {
containsNumbersGreaterThan10000++;
}
if (!has10000 && i == 10000) {
has10000 = true;
}
count++;
}
long end = System.currentTimeMillis();
System.out.println("first: " + first);
System.out.println("containsNumbersGreaterThan10000: " + containsNumbersGreaterThan10000);
System.out.println("has10000: " + has10000);
return end - start;
}
}
但从来没有显着。
findFirst可能是一个不好的例子,因为它只是在流为空时退出,但我想知道它是否有所作为。
我希望得到一个允许从一个流中进行多次计算的解决方案。 IntSummaryStatistics并不完全符合我的要求。我想我会留意@ florian-schaetz并坚持赞成可读性以获得微小的性能提升
答案 0 :(得分:5)
你不会三次遍历这个系列。
mostRecentMessageSentDate = messageInfoList
.stream()
.findFirst().orElse(new MessageInfo())
.getSentDate();
以上检查集合中是否有任何元素并根据此值返回值。它不需要经历整个系列。
unprocessedMessagesCount = messageInfoList
.stream()
.filter(messageInfo -> messageInfo.getProcessedDate() == null)
.count();
这个需要过滤掉没有处理日期的所有元素并对它们进行计数,因此这个元素会遍历整个集合。
hasAttachment = messageInfoList
.stream()
.anyMatch(messageInfo -> messageInfo.getAttachmentCount() > 0);
以上只需要遍历元素,直到找到带附件的消息。
因此,在三个流中,只需要其中一个来完成整个集合,在最坏的情况下,您需要进行两次迭代(第二个,可能是第三个流)
使用常规For-Each循环可能会更高效,但你真的需要它吗?如果您的收藏只包含一些对象,我就不会对它进行优化。
但是,使用传统的For-Each循环,您可以组合最后两个流:
int unprocessedMessagesCount = 0;
boolean hasAttachment = false;
for (MessageInfo messageInfo: messageInfoList) {
if (messageInfo.getProcessedDate() == null) {
unprocessedMessagesCount++;
}
if (hasAttachment == false && messageInfo.getAttachmentCount() > 0) {
hasAttachment = true;
}
}
如果你认为这是一个更好的解决方案(我也发现这些流更具可读性),这真的取决于你。我没有看到将三种流合并为一种方法的方法,至少不是以更易读的方式。