Enums 使用array.stream()比在数组上迭代有什么性能优势吗?
我需要迭代所有枚举值,检查它们是否用于构造int(称为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
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:well0b111
显然指的是问题中正好有三个常数的情况。如果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
是一个问题。