通用枚举到可迭代转换器 [关闭]
Posted
技术标签:
【中文标题】通用枚举到可迭代转换器 [关闭]【英文标题】:generic Enumeration to Iterable converter [closed] 【发布时间】:2012-01-02 02:59:33 【问题描述】:HttpServletRequest 使用了大量的 java.util.Enumeration。我想在 for-each 中使用它们,所以我需要将它们转换为可交互的。这不是问题,但是因为我有多个项目需要这个,所以我需要一个库来做到这一点。我宁愿不自己做——有没有支持这种装饰的标准库?
是否有内置构造可以将 Enumeration 转换为 Iterable?
【问题讨论】:
拥有 Iterator->Iterable 也很好,而且没有转换为列表的 O(n) 成本。 为 google guava 添加了增强票:code.google.com/p/guava-libraries/issues/detail?id=796 @Micheal, IAdapter - 从我引用的 javadoc 可以看出,他们无意这样做。票证也已提到idea graveyard,我会在我的回答中给出解释的要点 有趣的是:HttpServletResponse
使用了更常见的 Collection 接口。
我不同意这是题外话 - 提问者要求的解决方案可能是也可能不是图书馆
【参考方案1】:
看看这篇文章:http://www.java2s.com/Code/Java/Collections-Data-Structure/TreatanEnumerationasanIterable.htm
这似乎正是您所需要的。
更新 添加代码以供将来参考,以防链接损坏。
import java.util.Enumeration;
import java.util.Iterator;
/**
* @since 4.37
* @author Jaroslav Tulach
*/
public class Utils
public static <E> Iterable<E> iterable(final Enumeration<E> enumeration)
if (enumeration == null)
throw new NullPointerException();
return new Iterable<E>()
public Iterator<E> iterator()
return new Iterator<E>()
public boolean hasNext()
return enumeration.hasMoreElements();
public E next()
return enumeration.nextElement();
public void remove()
throw new UnsupportedOperationException();
;
;
【讨论】:
不,这根本不是我需要的。正如我所说,编写这段代码很容易,这不是我想要的。 @IAdaptor 你能提供更多信息吗?为什么这不是你想要的? 该代码的问题在于,通过 Iterable 创建的所有迭代器都将使用相同的枚举器。 @raisercostin,恕我直言,这根本不是问题。Iterable
是定义方法Iterator
的接口,该方法可以在每次调用时返回不同的迭代器。如果你用实现接口 Enumeration
的东西包装这个迭代器,你将使用从 iterator()
返回的迭代器。
不幸的是,如果您从与此处 ideone.com/4BxbiM 相同的枚举器创建两个新迭代器,则第一个迭代将消耗基本枚举器,并且不会为第二个迭代器留下任何内容。【参考方案2】:
java.util.Collections
有一个list
方法,可以将Enumeration
复制到List
,然后您可以在for-each 循环中使用它(请参阅javadoc)。
【讨论】:
您不能在 for-each 循环中直接使用Iterator
。
@Jeffrey:该死,你是对的,我没有考虑清楚(或正确阅读问题)。固定。
@Jeffrey 除非你把它包裹在 new Iterable<E>()public Iterator<E> iterator()return Iterators.forEnumeration(enum);
【参考方案3】:
这里是来自 Guava 的javadoc,关于将枚举转换为迭代器(不可迭代):
公共静态 UnmodifiableIterator forEnumeration(Enumeration枚举)
使枚举适应迭代器接口。
此方法在 Iterables 中没有等效方法,因为查看 枚举作为 Iterable 是不可能的。不过内容可以 使用复制到集合中 Collections.list(java.util.Enumeration)。
更多 apache commons collections 当前实现不支持 Java 5 功能和 API,例如 Iterable,因此没有机会。
然而,这些库中有一些方法允许您将枚举更改为可迭代的集合并使用它(尽管它们会隐式复制您的数据)。
例如,转换为带有EnumerationUtils.toList(enumeration) 的列表。
编辑:由于问题中的一些疑问,我将尝试总结为什么番石榴的制造者(和我)不觉得可以将枚举变成可迭代的。
一个可迭代对象创建迭代器实例,阅读代码(或 API)的人可以假设每次调用 iterator() 都会产生一个新的迭代器实例,从第一个元素开始枚举。如果我们在迭代器(或枚举)和可迭代对象之间进行简单的转换,那么 API 的用户需要知道对 iterator() 的调用会改变对象的状态,并且两次连续调用可能会表现得很奇怪。这是一个例子:
Iterable<String> iter = magicFunction(enumeration);
for (String s : iter)
if ("hello".equals(s))
break;
for (String s : iter)
if ("world".equals(s))
return true;
return false;
如果实现为简单转换 ( O(1) ) 对于不同的输入,上述方法的行为会有所不同:["hello","world"]
将返回 true
,而 ["world","hello"]
将返回 false
。这在查看代码时不会立即显现出来,并且可能是许多令人沮丧的错误的原因。因此,我认为不存在此实用方法是有意义的。
【讨论】:
关于 Guava 的“不可能”声明的愚蠢之处在于,我们实际上已经在我们的实用程序方法中实现了这个“不可能”Iterable。由于我们调用方法 toSingleUseIterable(),调用者很明显它只会工作一次。 魔术函数返回的Iterable可以缓存输出,只有在迭代通过缓存的索引时才继续使用enumeration.next()。 确实如此,这将节省每次调用该方法的 O(n) 成本,并用 O(n) 内存开销替换它。主要的缺点是您需要在迭代器的实例之间共享缓存,这可能会导致同步开销或潜在的错误,或者您可以将缓存复制到您构建的迭代器的任何实例中,但您可能只是复制整个枚举并用它完成 在 Java 8 中你可以使用:Iterators.forEnumeration(oldEnumeratorMethod()).forEachRemaining(e -> …);
【参考方案4】:
在我看来,文档化的方式是最简单的,所以不需要转换成迭代器:
https://docs.oracle.com/javase/1.5.0/docs/api/java/util/Enumeration.html
for (Enumeration<E> e = v.elements(); e.hasMoreElements();)
System.out.println(e.nextElement());
【讨论】:
【参考方案5】:您有两种解决方案:
首先是将枚举器消耗到一个可迭代的集合中(如@skaffman 所述)。正如@Michael 所指出的那样,这将添加 O(n)
如果您可以访问创建枚举器的方法,则可以将其包装到 Iterable 中而无需支付任何费用。在您的情况下,您可以使用以下方法创建 Iterable:
final Request request2 = request;
Iterable<String> headerNamesIterable = new Iterable<String>()
public Iterator<T> iterator()
return Iterators.forEnumeration(request2.getHeaderNames())
Iterable<String> headersIterableName1 = new Iterable<String>()
public Iterator<T> iterator()
return Iterators.forEnumeration(request2.getHeaders("name1"))
在这种情况下,您可以对由 Iterable 对象创建的迭代器进行多次迭代。
【讨论】:
以上是关于通用枚举到可迭代转换器 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章