私のアプリケーションでは、サードパーティのライブラリを使用しています(正確にはMongoDBのSpring Data)。
このライブラリのメソッドはを返しIterable<T>
ますが、私のコードの残りの部分はを期待していCollection<T>
ます。
どこかに、一方を他方にすばやく変換できるユーティリティメソッドはありますか?foreach
このような単純なことのために、コード内に一連のループを作成することは避けたいと思います。
私のアプリケーションでは、サードパーティのライブラリを使用しています(正確にはMongoDBのSpring Data)。
このライブラリのメソッドはを返しIterable<T>
ますが、私のコードの残りの部分はを期待していCollection<T>
ます。
どこかに、一方を他方にすばやく変換できるユーティリティメソッドはありますか?foreach
このような単純なことのために、コード内に一連のループを作成することは避けたいと思います。
Guavaでは、他の同様のメソッドの中でも、 Lists.newArrayList (Iterable)またはSets.newHashSet(Iterable )を使用できます。もちろん、これによりすべての要素がメモリにコピーされます。Iterable
それが受け入れられない場合は、これらで動作するコードは、ではなく取る必要があると思いますCollection
。Guavaは、 (またはなどの)Collection
を使用して実行できることを実行するための便利なメソッドも提供しますが、パフォーマンスへの影響はより明白です。Iterable
Iterables.isEmpty(Iterable)
Iterables.contains(Iterable, Object)
JDK 8+では、追加のライブラリを使用せずに:
Iterator<T> source = ...;
List<T> target = new ArrayList<>();
source.forEachRemaining(target::add);
編集:上記のものはIterator
. を扱っている場合はIterable
、
iterable.forEach(target::add);
このために独自のユーティリティ メソッドを作成することもできます。
public static <E> Collection<E> makeCollection(Iterable<E> iter) {
Collection<E> list = new ArrayList<E>();
for (E item : iter) {
list.add(item);
}
return list;
}
以下を使用した Java 8 による簡潔なソリューションjava.util.stream
:
public static <T> List<T> toList(final Iterable<T> iterable) {
return StreamSupport.stream(iterable.spliterator(), false)
.collect(Collectors.toList());
}
IteratorUtils
fromcommons-collections
が役立つ場合があります(ただし、最新の安定バージョン 3.2.1 ではジェネリックはサポートされていません)。
@SuppressWarnings("unchecked")
Collection<Type> list = IteratorUtils.toList(iterable.iterator());
バージョン 4.0 (現時点では SNAPSHOT にあります) はジェネリックをサポートしており、@SuppressWarnings
.
更新: CactoosIterableAsList
から確認してください。
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());
}
}
その際、すべてのコレクションは有限であるのに対し、Iterable には何の約束もないことを忘れないでください。何かが Iterable の場合、Iterator を取得できます。それだけです。
for (piece : sthIterable){
..........
}
次のように拡張されます。
Iterator it = sthIterable.iterator();
while (it.hasNext()){
piece = it.next();
..........
}
it.hasNext() が false を返す必要はありません。したがって、一般的なケースでは、すべての Iterable を Collection に変換できるとは期待できません。たとえば、すべての正の自然数を反復処理したり、同じ結果を何度も生成するサイクルを含むものを反復処理したりできます。
それ以外の場合: Atrey の回答は非常に適切です。
I came across a similar situation while trying to fetch a List
of Project
s, 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.
これはあなたの質問に対する答えではありませんが、あなたの問題に対する解決策だと思います。インターフェイスorg.springframework.data.repository.CrudRepository
には実際に返すメソッドjava.lang.Iterable
がありますが、このインターフェイスを使用しないでください。あなたの場合は、代わりにサブインターフェースを使用してくださいorg.springframework.data.mongodb.repository.MongoRepository
。このインターフェイスには、 型のオブジェクトを返すメソッドがありますjava.util.List
。
カスタム ユーティリティを使用して、既存のコレクションがあればそれをキャストします。
主要:
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 の一部になっていると思いますが、まだ見つかりません。
、、、、、、、、またはを呼び出すとすぐにcontains
、containsAll
とにかくequals
要素をトラバースする必要があります。hashCode
remove
retainAll
size
toArray
たまになどのメソッドを呼び出すだけの場合は、コレクションを怠惰に作成する方がisEmpty
よいclear
と思います。ArrayList
たとえば、以前に繰り返された要素を格納するためのバッキングを持つことができます。
私はどのライブラリにもそのようなクラスがあることを知りませんが、書くのはかなり簡単な練習になるはずです。
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の回答に触発されました。
これは、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);
}
}
2つの備考