web-dev-qa-db-ja.com

汎用列挙型から反復可能コンバーター

HttpServletRequestは多くのJava.util.Enumerationを使用しています。 for-eachで使用したいので、interableに変換する必要があります。これは問題ではありませんが、これを必要とするプロジェクトが複数あるので、これを行うにはライブラリが必要です。自分で作成したくないのですが、この種の装飾をサポートする標準ライブラリはありますか?

列挙型を反復可能に変換するための組み込み構造はありますか?

34
IAdapter

Java.util.Collectionsにはlistメソッドがあります。このメソッドはEnumerationListにコピーし、for-eachループで使用できます( javadoc を参照)。 )。

45
skaffman

列挙型からイテレータへの変換に関するGuavaの javadoc (反復不可)は次のとおりです。

public static UnmodizableIterator forEnumeration(Enumeration enumeration)

列挙型をイテレータインターフェイスに適合させます。

列挙型をIterableとして表示することは不可能であるため、このメソッドにはIterablesに相当するものがありません。ただし、Collections.list(Java.util.Enumeration)を使用して、コンテンツをコレクションにコピーできます。

さらに多くのApacheCommons Collectionは、現在の実装がJava Iterableなどの5つの機能とAPIをサポートしていないため、そこにチャンスはありません。

ただし、これらのライブラリには、列挙型を反復可能なコレクションに変更して使用できるメソッドがいくつかあります(ただし、暗黙的にデータをコピーします)。

たとえば、 EnumerationUtils.toList(enumeration) でリストに変換します。

編集:質問のいくつかの質問のために、グアバのメーカー(および私)が列挙を反復可能にできると感じない理由を要約しようと思います。

Iterableはイテレータインスタンスを作成します。コード(またはAPI)を読んでいる人は、iterator()を呼び出すたびに、最初の要素から列挙を開始する新しいイテレータインスタンスが生成されると想定できます。イテレータ(または列挙型)とイテレータの間で単純な変換を行う場合、APIのユーザーは、iterator()の呼び出しがオブジェクトの状態を変更し、2つの連続した呼び出しが奇妙に動作する可能性があることを知る必要があります。ここに例があります:

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を返します。これは、コードを見るとすぐにはわかりません。多くの苛立たしいバグの原因となる可能性があります。したがって、このユーティリティメソッドが存在しないことは理にかなっていると思います。

16
Asaf

私の意見では、文書化された方法が最も簡単なので、イテレータに変換する必要はありません。

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());
9
Krauss

この記事を見てください: 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();
                  }
              };
          }
      };
  }    
}
4
AlexR

2つの解決策があります。

1つは、列挙子をIterableであるコレクションに消費することです(@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オブジェクトによって作成されたイテレータで複数回繰り返すことができます。

2
raisercostin