Enums 使用array.stream()比在数组上迭代有什么性能优势吗?

Enums 使用array.stream()比在数组上迭代有什么性能优势吗?,enums,java-8,java-stream,Enums,Java 8,Java Stream,我需要迭代所有枚举值,检查它们是否用于构造int(称为input),如果是,则将它们添加到集合中(称为usefulEnums)。我可以使用streams API或迭代所有枚举来完成此任务。使用Arrays.stream()比在values()上迭代的传统方法有什么好处吗 enum TestEnum { VALUE1, VALUE2, VALUE3 }; Set<TestEnum> usefulEnums = new HashSet<>(); Arra

我需要迭代所有枚举值,检查它们是否用于构造int(称为
input
),如果是,则将它们添加到集合中(称为
usefulEnums
)。我可以使用streams API或迭代所有枚举来完成此任务。使用
Arrays.stream()
比在
values()上迭代的传统方法有什么好处吗

   enum TestEnum { VALUE1, VALUE2, VALUE3 };

   Set<TestEnum> usefulEnums = new HashSet<>();

   Arrays.stream(TestEnum.values())
            .filter(t -> (input & t.getValue()) != 0)
            .forEach(usefulEnums::add);

    for (TestEnum t : TestEnum.values()) {
        if ((input & t.getValue()) != 0) {
            usefulEnums.add(t);
        }
    }
enum TestEnum{VALUE1,VALUE2,VALUE3};
Set usefulEnums=new HashSet();
Arrays.stream(TestEnum.values())
.filter(t->(输入&t.getValue())!=0)
.forEach(usefulEnums::add);
for(TestEnum t:TestEnum.values()){
如果((input&t.getValue())!=0){
添加(t);
}
}

对于这个短操作,循环的
将更快(快纳秒),但对我来说,流操作更详细,它确切地告诉我们这里正在做什么。这就像是斜读

您还可以直接收集到
哈希集

Arrays.stream(TestEnum.values())
        .filter(t -> (input & t.getValue()) != 0)
        .collect(Collectors.toCollection(HashSet::new));
霍尔格一如既往地提供了宝贵的意见,这让情况变得更加美好:

EnumSet<TestEnum> filtered = EnumSet.allOf(TestEnum.class).stream()
            .filter(t -> (input & t.getValue()) != 0)
            .collect(Collectors.toCollection(() -> EnumSet.noneOf(TestEnum.class)));
EnumSet filtered=EnumSet.allOf(TestEnum.class).stream()
.filter(t->(输入&t.getValue())!=0)
.collect(Collectors.toCollection(()->EnumSet.noneOf(TestEnum.class));

如果您关心效率,您应该考虑:

Set<TestEnum> usefulEnums = EnumSet.allOf(TestEnum.class);
usefulEnums.removeIf(t -> (input & t.getValue()) == 0);
Set usefulEnums=EnumSet.allOf(TestEnum.class);
usefulEnums.removeIf(t->(input&t.getValue())==0);
请注意,当您必须迭代某个类型的所有
enum
常量时,使用
EnumSet.allOf(EnumType.class).stream()
可以完全避免创建
EnumType.values()
数组,但是,大多数
enum
类型没有足够的常量来实现这一点。此外,JVM的优化器可能会删除临时数组创建


但是对于这个特定任务,如果结果应该是
,使用
枚举集
而不是
哈希集
,甚至可以改进使用
的后续操作。创建一个包含所有常量的
EnumSet
并删除上述解决方案中不需要的常量,这意味着只需使用
0b111
初始化
long
,然后清除不匹配元素的位。

在通常情况下,您只需要一个
集合,而不是
哈希集,
Collectors.toSet()
更可取。@索洛莫诺夫的秘密:当元素是枚举常量时,比如
TestEnum
,最好使用
Collectors.toCollection(()->EnumSet.noneOf(TestEnum.class))
,尽管获取与谓词匹配的所有
enum
常量的任务有一个简单的直接解决方案…@Holger-awesome。我不知道为什么我总是认为
EnumSet。没有一个
allOf
是不可变的。@Eugene这是一个令人困惑的API。这些方法类似于
Collections.emptySet()
等等。但是我不确定API设计者是否有太多的选择,因为这些工厂方法根据给定类型的枚举元素的数量返回不同的类,所以构造函数是不够的。也许
EnumSet.create
会更清晰,但它会破坏
noneOf
allOf
@Solomonoff的
Collections.emptySet()
名称之间的一致性。这就是为什么我从未尝试将它们作为可变项使用。
意味着仅使用0b111初始化long,除非您有超过64个条目,否则将使用
JumboEnumSet
。关于EnumSet的好观点。allOf
@Eugene:well
0b111
显然指的是问题中正好有三个常数的情况。如果
enum
64个
常量,它将是
0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111
数组,如果它有更多,则有一个
long[]
数组,但随后,更大的
TestEnum[
数组的缺失可能变得明显,将
EnumSet
的优势发挥得更大。@霍尔格你能解释一下
意味着只需用0b111
初始化一个long吗?
EnumSet
为每个
enum
常量分配一位,并将其设置为
1
,如果该常量包含在内。因此,对于有三个常量的枚举,它使用一个
long
变量和
EnumSet。allOf
将初始化它以设置所有三位,即
0b111
,这意味着“所有常量都存在”。然后,
removeIf
将只清除与谓词匹配的位。因此,与HashSet不同,不需要分配或填充数组。如果您对它不熟悉,
0b111
是一个问题。