Java 8的方式与枚举工作
我想知道在Java 8中处理枚举值的最好方法是什么。 特别是当你需要获取所有的值并将其添加到某个地方时,例如,假设我们有以下枚举:
public enum Letter { A, B, C, D; }
我当然可以做到以下几点:
for (Letter l : Letter.values()) { foo(l); }
但是,我也可以将以下方法添加到枚举定义中:
public static Stream<Letter> stream() { return Arrays.stream(Letter.values()); }
然后从上面replace为:
Letter.stream().forEach(l -> foo(l));
这种方法是否正确,或者在devise或性能方面有问题? 另外,为什么不枚举有一个stream()方法?
三个问题:三部分答案:
从devise的angular度来看可以吗?
绝对。 没有错。 如果你需要做大量迭代你的枚举,streamAPI是干净的方式去隐藏锅炉板后面的一个小方法是好的。 尽pipe我认为OldCumudgeon的版本更好。
从表演的angular度来看,这样可以吗?
这很可能没有关系。 大多数时候,枚举不是那么大。 因此,无论是99.9%的情况下,一种方法或另一种方法的开销可能都不重要。
当然,它有0.1%的地方。 在这种情况下:用您的真实世界的数据和消费者来衡量。
如果我不得不打赌,我预计for each
循环都会更快,因为它更直接地映射到内存模型,但不要在谈论性能时猜测,并且在实际需要调整之前不要调整。 以一种正确的方式编写代码,易于阅读,只有担心代码风格的性能。
为什么Enums没有正确集成到Stream API中?
如果您将Java的Stream API与许多其他语言的等效语言进行比较,则显得非常有限。 有不同的片段丢失(例如,可重复使用的Streams和Optionals作为Streams)。 另一方面,实现Stream API当然是API的一个巨大变化。 它被推迟了多次,这是有原因的。 所以我想Oracle是想把这个变化限制在最重要的用例上。 枚举不用那么多。 当然,每个项目都有其中的一些,但与列表和其他集合的数量相比,它们并没有什么特点。 即使你有一个枚举,在很多情况下,你都不会重复它。 另一方面,列表和集合几乎每次都可能迭代。 我认为这就是为什么Enums没有自己的适配器到Stream世界的原因。 我们将看看是否有更多的这将被添加到未来的版本。 在那之前你总是可以使用Arrays.stream
。
我会去EnumSet
。 由于forEach()
也是在Iterable
定义的,所以可以避免完全创buildstream:
EnumSet.allOf(Letter.class).forEach(x -> foo(x));
或者用一个方法参考:
EnumSet.allOf(Letter.class).forEach(this::foo);
尽pipe如此,老式的循环感觉有点简单:
for (Letter x : Letter.values()) { foo(x); }
我的猜测是枚举的大小是有限的(即大小不受语言的限制,但受使用的限制),因此它们不需要本地streamAPI。 当你不得不操纵变换并重新收集stream中的元素时,stream是非常好的。 这些并不是Enum的常见用例(通常是迭代枚举值,但很less需要转换,映射和收集它们)。
如果您只需要对每个元素执行操作,则可能只应公开一个forEach方法
public static void forEach(Consumer<Letter> action) { Arrays.stream(Letter.values()).forEach(action); } .... //example of usage Letter.forEach(e->System.out.println(e));
我认为获得一个枚举常量Stream
的最短代码是Stream.of(Letter.values())
。 它不像Letter.values().stream()
那么好,但这是数组的问题,而不是特定的枚举。
另外,为什么不枚举有一个
stream()
方法?
你是对的,最好的可能的电话将是Letter.stream()
。 不幸的是一个类不能有两个具有相同签名的方法,所以不可能为每个枚举隐式添加一个静态方法stream()
(就像每个枚举都有一个隐式添加的静态方法values()
)会打破已经有一个静态或实例方法没有参数的所有现有的枚举被称为stream()
。
这个方法好吗?
我想是这样。 缺点是stream
是静态方法,所以无法避免代码重复; 它将不得不分别添加到每个枚举。