Java 8 使用枚举的方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29922296/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 08:49:47  来源:igfitidea点击:

Java 8 way to work with an enum

javaenumsjava-8

提问by Rumal

I'm wondering what the best way is in Java 8 to work with all the values of an enum. Specifically when you need to get all the values and add it to somewhere, for example, supposing that we have the following enum:

我想知道在 Java 8 中使用枚举的所有值的最佳方法是什么。特别是当您需要获取所有值并将其添加到某处时,例如,假设我们有以下枚举:

public enum Letter {
 A, B, C, D;
}

I could of course do the following:

我当然可以做到以下几点:

for (Letter l : Letter.values()) {
    foo(l);
}

But, I could also add the following method to the enum definition:

但是,我也可以将以下方法添加到枚举定义中:

public static Stream<Letter> stream() {
    return Arrays.stream(Letter.values());
}

And then replace the for from above with:

然后将上面的 for 替换为:

Letter.stream().forEach(l -> foo(l));

Is this approach OK or does it have some fault in design or performance? Moreover, why don't enums have a stream() method?

这种方法是否可以,或者它在设计或性能上有什么问题?此外,为什么枚举没有 stream() 方法?

采纳答案by Jens Schauder

Three questions: three-part answer:

三个问题:三部分答案:

Is it okay from a design point of view?

从设计的角度来看可以吗?

Absolutely. Nothing wrong with it. If you need to do lots of iterating over your enum, the stream API is the clean way to go and hiding the boiler plate behind a little method is fine. Although I'd consider OldCumudgeon's versioneven better.

绝对地。没什么不对的。如果您需要对枚举进行大量迭代,那么流 API 是一种干净的方法,将样板隐藏在一个小方法后面就可以了。虽然我认为OldCumudgeon版本更好。

Is it okay from a performance point of view?

从性能的角度来看可以吗?

It most likely doesn't matter. Most of the time, enums are not that big. Therefore, whatever overhead there is for one method or the other probably doesn't matter in 99.9% of the cases.

这很可能无关紧要。大多数时候,枚举并没有那么大。因此,在 99.9% 的情况下,一种方法或另一种方法的开销可能无关紧要。

Of course, there are the 0.1% where it does. In that case: measure properly, with your real-world data and consumers.

当然,也有 0.1% 的地方。在这种情况下:使用您的真实数据和消费者进行适当的测量。

If I had to bet, I'd expect the for eachloop to be faster, since it maps more directly to the memory model, but don't guess when talking performance, and don't tune before there is actual need for tuning. Write your code in a way that is correct first, easy to read second and only then worry about performance of code style.

如果我不得不打赌,我希望for each循环更快,因为它更直接地映射到内存模型,但在谈论性能时不要猜测,并且在实际需要调整之前不要进行调整。首先以正确的方式编写代码,其次易于阅读,然后才担心代码风格的性能。

Why aren't Enums properly integrated into the Stream API?

为什么枚举没有正确集成到 Stream API 中?

If you compare Java's Stream API to the equivalent in many other languages, it appears seriously limited. There are various pieces that are missing (reusable Streams and Optionals as Streams, for example). On the other hand, implementing the Stream API was certainly a huge change for the API. It was postponed multiple times for a reason. So I guess Oracle wanted to limit the changes to the most important use cases. Enums aren't used that much anyway. Sure, every project has a couple of them, but they're nothing compared to the number of Lists and other Collections. Even when you have an Enum, in many cases you won't ever iterate over it. Lists and Sets, on the other hand, are probably iterated over almost every time. I assume that these were the reasons why the Enums didn't get their own adapter to the Stream world. We'll see whether more of this gets added in future versions. And until then you always can use Arrays.stream.

如果将 Java 的 Stream API 与许多其他语言中的等价物进行比较,就会发现它受到严重限制。缺少各种部分(例如,可重用的 Streams 和 Optionals 作为 Streams)。另一方面,实现 Stream API 对 API 来说无疑是一个巨大的变化。由于某种原因,它被多次推迟。所以我猜 Oracle 希望将更改限制在最重要的用例上。无论如何,枚举并不常用。当然,每个项目都有几个,但与列表和其他集合的数量相比,它们算不了什么。即使你有一个 Enum,在很多情况下你也不会迭代它。另一方面,列表和集合可能几乎每次都被迭代。我认为这些是 Enum 没有为 Stream 世界获得自己的适配器的原因。我们' 将看看是否会在未来的版本中添加更多内容。在那之前你总是可以使用Arrays.stream.

回答by Giovanni

My guessis that enums are limited in size (i.e the size is not limited by language but limited by usage)and thus they don't need a nativestream api. Streams are very good when you have to manipulate transform and recollect the elements in a stream; these are not common uses case for Enum (usually you iterate over enum values, but rarely you need to transform, map and collect them).

我的猜测是枚举的大小有限(即大小不受语言限制,但受使用限制),因此它们不需要本机流 api。当您必须操作转换并重新收集流中的元素时,流非常有用;这些不是 Enum 的常见用例(通常您迭代枚举值,但很少需要转换、映射和收集它们)。

If you need only to do an action over each elements perhaps you should expose only a forEach method

如果你只需要对每个元素做一个动作,也许你应该只公开一个 forEach 方法

     public static void forEach(Consumer<Letter> action) {
            Arrays.stream(Letter.values()).forEach(action);
     }

     .... //example of usage
     Letter.forEach(e->System.out.println(e));

回答by Paul Boddington

I think the shortest code to get a Streamof enum constants is Stream.of(Letter.values()). It's not as nice as Letter.values().stream()but that's an issue with arrays, not specifically enums.

我认为获取Stream枚举常量的最短代码是Stream.of(Letter.values()). 它没有那么好,Letter.values().stream()但这是数组的问题,而不是具体的枚举。

Moreover, why don't enums have a stream()method?

此外,为什么枚举没有stream()方法?

You are right that the nicest possible call would be Letter.stream(). Unfortunately a class cannot have two methods with the same signature, so it would not be possible to implicitly add a static method stream()to every enum (in the same way that every enum has an implicitly added static method values()) as this would break every existing enum that already has a static or instance method without parameters called stream().

你说得对,最好的调用是Letter.stream()。不幸的是,一个类不能有两个具有相同签名的方法,因此不可能向stream()每个枚举隐式添加一个静态方法(就像每个枚举都有一个隐式添加的静态方法一样values()),因为这会破坏每个现有的枚举已经有一个没有参数的静态或实例方法称为stream()

Is this approach OK?

这种方法行吗?

I think so. The drawback is that streamis a static method, so there is no way to avoid code duplication; it would have to be added to every enum separately.

我想是这样。缺点是stream是静态方法,无法避免代码重复;它必须单独添加到每个枚举中。

回答by Natix

I'd go for EnumSet. Because forEach()is also defined on Iterable, you can avoid creating the stream altogether:

我会去EnumSet。因为forEach()也在 上定义Iterable,您可以完全避免创建流:

EnumSet.allOf(Letter.class).forEach(x -> foo(x));

Or with a method reference:

或者使用方法参考:

EnumSet.allOf(Letter.class).forEach(this::foo);

Still, the oldschool for-loop feels a bit simpler:

尽管如此,老派的 for 循环感觉有点简单:

for (Letter x : Letter.values()) {
    foo(x);
}