467

私のアプリケーションでは、サードパーティのライブラリを使用しています(正確にはMongoDBのSpring Data)。

このライブラリのメソッドはを返しIterable<T>ますが、私のコードの残りの部分はを期待していCollection<T>ます。

どこかに、一方を他方にすばやく変換できるユーティリティメソッドはありますか?foreachこのような単純なことのために、コード内に一連のループを作成することは避けたいと思います。

4

22 に答える 22

399

Guavaでは、他の同様のメソッドの中でも、 Lists.newArrayList (Iterable)またはSets.newHashSet(Iterable )を使用できます。もちろん、これによりすべての要素がメモリにコピーされます。Iterableそれが受け入れられない場合は、これらで動作するコードは、ではなく取る必要があると思いますCollection。Guavaは、 (またはなどの)Collectionを使用して実行できることを実行するための便利なメソッドも提供しますが、パフォーマンスへの影響はより明白です。IterableIterables.isEmpty(Iterable)Iterables.contains(Iterable, Object)

于 2011-06-20T20:05:18.597 に答える
397

JDK 8+では、追加のライブラリを使用せずに:

Iterator<T> source = ...;
List<T> target = new ArrayList<>();
source.forEachRemaining(target::add);

編集:上記のものはIterator. を扱っている場合はIterable

iterable.forEach(target::add);
于 2015-05-27T06:05:46.810 に答える
101

このために独自のユーティリティ メソッドを作成することもできます。

public static <E> Collection<E> makeCollection(Iterable<E> iter) {
    Collection<E> list = new ArrayList<E>();
    for (E item : iter) {
        list.add(item);
    }
    return list;
}
于 2011-06-20T20:14:55.863 に答える
98

以下を使用した Java 8 による簡潔なソリューションjava.util.stream:

public static <T> List<T> toList(final Iterable<T> iterable) {
    return StreamSupport.stream(iterable.spliterator(), false)
                        .collect(Collectors.toList());
}
于 2014-06-02T14:25:40.050 に答える
50

IteratorUtilsfromcommons-collectionsが役立つ場合があります(ただし、最新の安定バージョン 3.2.1 ではジェネリックはサポートされていません)。

@SuppressWarnings("unchecked")
Collection<Type> list = IteratorUtils.toList(iterable.iterator());

バージョン 4.0 (現時点では SNAPSHOT にあります) はジェネリックをサポートしており、@SuppressWarnings.

更新: CactoosIterableAsListから確認してください。

于 2013-04-28T14:12:25.110 に答える
24

CollectionUtilsから:

List<T> targetCollection = new ArrayList<T>();
CollectionUtils.addAll(targetCollection, iterable.iterator())

このユーティリティ メソッドの完全なソースは次のとおりです。

public static <T> void addAll(Collection<T> collection, Iterator<T> iterator) {
    while (iterator.hasNext()) {
        collection.add(iterator.next());
    }
}
于 2011-06-20T20:07:29.543 に答える
14

その際、すべてのコレクションは有限であるのに対し、Iterable には何の約束もないことを忘れないでください。何かが Iterable の場合、Iterator を取得できます。それだけです。

for (piece : sthIterable){
..........
}

次のように拡張されます。

Iterator it = sthIterable.iterator();
while (it.hasNext()){
    piece = it.next();
..........
}

it.hasNext() が false を返す必要はありません。したがって、一般的なケースでは、すべての Iterable を Collection に変換できるとは期待できません。たとえば、すべての正の自然数を反復処理したり、同じ結果を何度も生成するサイクルを含むものを反復処理したりできます。

それ以外の場合: Atrey の回答は非常に適切です。

于 2012-08-30T06:50:41.300 に答える
14

I came across a similar situation while trying to fetch a List of Projects, rather than the default Iterable<T> findAll() declared in CrudRepository interface. So, in my ProjectRepository interface (which extends from CrudRepository), I simply declared the findAll() method to return a List<Project> instead of Iterable<Project>.

package com.example.projectmanagement.dao;

import com.example.projectmanagement.entities.Project;
import org.springframework.data.repository.CrudRepository;
import java.util.List;

public interface ProjectRepository extends CrudRepository<Project, Long> {

    @Override
    List<Project> findAll();
}

This is the simplest solution, I think, without requiring conversion logic or usage of external libraries.

于 2020-05-30T04:14:53.807 に答える
9

これはあなたの質問に対する答えではありませんが、あなたの問題に対する解決策だと思います。インターフェイスorg.springframework.data.repository.CrudRepositoryには実際に返すメソッドjava.lang.Iterableがありますが、このインターフェイスを使用しないでください。あなたの場合は、代わりにサブインターフェースを使用してくださいorg.springframework.data.mongodb.repository.MongoRepository。このインターフェイスには、 型のオブジェクトを返すメソッドがありますjava.util.List

于 2013-06-18T12:04:08.120 に答える
7

カスタム ユーティリティを使用して、既存のコレクションがあればそれをキャストします。

主要:

public static <T> Collection<T> toCollection(Iterable<T> iterable) {
    if (iterable instanceof Collection) {
        return (Collection<T>) iterable;
    } else {
        return Lists.newArrayList(iterable);
    }
}

上記では ImmutableList を使用するのが理想的ですが、ImmutableCollection では null を使用できないため、望ましくない結果が生じる可能性があります。

テスト:

@Test
public void testToCollectionAlreadyCollection() {
    ArrayList<String> list = Lists.newArrayList(FIRST, MIDDLE, LAST);
    assertSame("no need to change, just cast", list, toCollection(list));
}

@Test
public void testIterableToCollection() {
    final ArrayList<String> expected = Lists.newArrayList(FIRST, null, MIDDLE, LAST);

    Collection<String> collection = toCollection(new Iterable<String>() {
        @Override
        public Iterator<String> iterator() {
            return expected.iterator();
        }
    });
    assertNotSame("a new list must have been created", expected, collection);
    assertTrue(expected + " != " + collection, CollectionUtils.isEqualCollection(expected, collection));
}

コレクションのすべてのサブタイプ (セット、リストなど) に同様のユーティリティを実装します。これらはすでに Guava の一部になっていると思いますが、まだ見つかりません。

于 2014-09-04T08:35:13.950 に答える
6

、、、、、、、、またはを呼び出すとすぐにcontainscontainsAllとにかくequals要素をトラバースする必要があります。hashCoderemoveretainAllsizetoArray

たまになどのメソッドを呼び出すだけの場合は、コレクションを怠惰に作成する方がisEmptyよいclearと思います。ArrayListたとえば、以前に繰り返された要素を格納するためのバッキングを持つことができます。

私はどのライブラリにもそのようなクラスがあることを知りませんが、書くのはかなり簡単な練習になるはずです。

于 2011-06-20T20:04:20.683 に答える
6

Java 8 では、これを実行して to からすべての要素を追加し、それを返すことができIterableますCollection

public static <T> Collection<T> iterableToCollection(Iterable<T> iterable) {
  Collection<T> collection = new ArrayList<>();
  iterable.forEach(collection::add);
  return collection;
}

@Afreysの回答に触発されました。

于 2014-04-24T14:05:37.620 に答える
4

これは、Java 8 でこれを行う優れた方法の SSCCE です。

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class IterableToCollection {
    public interface CollectionFactory <T, U extends Collection<T>> {
        U createCollection();
    }

    public static <T, U extends Collection<T>> U collect(Iterable<T> iterable, CollectionFactory<T, U> factory) {
        U collection = factory.createCollection();
        iterable.forEach(collection::add);
        return collection;
    }

    public static void main(String[] args) {
        Iterable<Integer> iterable = IntStream.range(0, 5).boxed().collect(Collectors.toList());
        ArrayList<Integer> arrayList = collect(iterable, ArrayList::new);
        HashSet<Integer> hashSet = collect(iterable, HashSet::new);
        LinkedList<Integer> linkedList = collect(iterable, LinkedList::new);
    }
}
于 2016-08-08T06:54:30.607 に答える
2

2つの備考

  1. foreach ループを使用するために Iterable を Collection に変換する必要はありません - Iterable はそのようなループで直接使用できます。構文上の違いはないため、元の質問がなぜ尋ねられたのかまったくわかりません。
  2. Iterable を Collection に変換する推奨される方法は安全ではありません (CollectionUtils にも同じことが関係しています) - next() メソッドへの後続の呼び出しが異なるオブジェクト インスタンスを返すという保証はありません。さらに、この懸念は純粋に理論的なものではありません。たとえば、Hadoop Reducer の reduce メソッドに値を渡すために使用される Iterable 実装は、フィールド値が異なるだけで、常に同じ値インスタンスを返します。したがって、上記の makeCollection (または CollectionUtils.addAll(Iterator)) を適用すると、すべて同一の要素を持つコレクションになります。
于 2013-02-20T12:15:37.227 に答える