我读了这篇Java 8官方文档:
Streams可能有也可能没有已定义的遭遇顺序。是否 一个流有一个遭遇顺序取决于源和 中间操作。某些流源(例如List或 数组)本质上是有序的,而其他的(如HashSet) 不是。
如果订购了一个流,则重复执行相同的操作 相同来源的流管道将产生相同的 结果;如果没有订购,可能会产生重复执行 不同的结果。
试图通过此代码了解上述行为
public class StreamOrderValidator
{
public static void main( String[] args )
{
String[] colors=new String[] {"red","green","blue","orange"};
List<String> colorsList=Arrays.asList(colors);
HashSet<String> colorsSet=new HashSet<>();
colorsSet.addAll(colorsList);
System.out.println(colorsSet); // [red, orange, green, blue]
List<String> processedColorsSet = processStream(colorsSet.stream());
System.out.println(processedColorsSet); // [RED, ORANGE, GREEN, BLUE]
}
private static List<String> processStream(Stream<String> colorStream) {
List<String> processedColorsList = colorStream.filter(s->s.length()<=6).
map(String::toUpperCase).collect(Collectors.toList());
return processedColorsList;
}
}
我多次运行此代码,结果流中元素的顺序始终相同(显示为注释)。我无法弄清楚这是如何证明以上引用的文字“没有为无序集合保留的命令”。
我肯定误解了javadocs提取的文本。
答案 0 :(得分:5)
这里确实存在一些误解。 HashSet
或任何Set
与订单无关,除非TreeSet
基于Comparator
订购。
目前,在 java-8 下,一旦你将元素放入HashSet
(并且不要改变它),就会有一个如何布局元素的顺序;但同样,在你不添加或删除任何一个的情况下。这可以随时改变,所以不要依赖它。
例如运行此:
String[] colors = new String[] { "red", "green", "blue", "orange" };
List<String> colorsList = Arrays.asList(colors);
HashSet<String> colorsSet = new HashSet<>();
colorsSet.addAll(colorsList);
System.out.println(colorsSet);
无论在目前的java-8 下多少次,你总是获得相同的输出:
[red, orange, green, blue]
但是一旦你做了一些内部重新洗牌:
for (int i = 0; i < 1000; ++i) {
colorsSet.add("" + i);
}
for (int i = 0; i < 1000; ++i) {
colorsSet.remove("" + i);
}
System.out.println(colorsSet); // [blue, red, green, orange]
您可以看到输出更改,因为Set
没有订单。
要点是没有顺序,事实上你确实看到订单并不是每次都发生的保证 - 在java-8中可能会有一个破坏这个顺序的构建。事实上,例如java-9
很容易观察到 - 新的Set
存在随机化模式。
如果多次运行,结果会有所不同:
Set<String> set = Set.of("red", "green", "blue", "orange");
System.out.println(set);
很明显,stream
来自Set
这样的订单将无法得到保证,因此您确实会看到不同的运行结果。
答案 1 :(得分:4)
您所看到的基本上是运气,您正在流式传输的HashSet按顺序返回值。如果随着时间的推移添加了足够的值,最终会看到来自流的不同结果,因为HashSet的底层HashMap必须调整自身并重新排序。
你提供的(四种颜色)偶然会每次都返回相同的结果,因为底层的HashMap不需要调整自身的大小并重新排序值。
请注意,根据Java API文档,HashSet由HashMap支持,此问题及其接受的答案涵盖了您通过解释HashMap的行为而看到的内容:
答案 2 :(得分:2)
重复执行可能会产生不同的结果。
这个might
字。即使它不保证订单,也不意味着订单每次都是随机的。元素基于hashcode
放置。
尝试一些不同的值:
String[] colors=new String[] {"5reegdfg","fsdfsd6546","fsdfxvc4","77ggg"};
List<String> colorsList=Arrays.asList(colors);
HashSet<String> intSet =new HashSet<>();
intSet.addAll(colorsList);
intSet.forEach(e -> System.out.print(e + " "));
System.out.println();
intSet.add("fvcxbxb78ok");
intSet.forEach(e -> System.out.print( e + " "));
输出是这样的:
fsdfxvc4 5reegdfg 77ggg fsdfsd6546
fsdfxvc4 fvcxbxb78ok 5reegdfg 77ggg fsdfsd6546
如您所见,此示例中的顺序不同。