java - संग्रह में Iterable बदलने के लिए आसान तरीका




collections (11)

Java.util.stream का उपयोग कर जावा 8 के साथ संक्षिप्त समाधान:

public static <T> List<T> toList(final Iterable<T> iterable) {
    return StreamSupport.stream(iterable.spliterator(), false)
                        .collect(Collectors.toList());
}

मेरे आवेदन में मैं तीसरे पक्ष की लाइब्रेरी का उपयोग करता हूं (मोंगो डीबी के लिए वसंत डेटा सटीक होना)।

इस लाइब्रेरी के तरीके Iterable<T> , जबकि मेरे शेष कोड Collection<T> अपेक्षा करते हैं।

क्या वहां कोई उपयोगिता विधि है जो मुझे तुरंत एक दूसरे को परिवर्तित करने देगी। मैं इस तरह की एक साधारण चीज़ के लिए अपने कोड में foreach लूप का एक समूह बनाने से बचना चाहता हूं।


आप इसके लिए अपनी खुद की उपयोगिता विधि भी लिख सकते हैं:

public static <E> Collection<E> makeCollection(Iterable<E> iter) {
    Collection<E> list = new ArrayList<E>();
    for (E item : iter) {
        list.add(item);
    }
    return list;
}

जावा 8 में आप Iterable से Collection सभी तत्वों को जोड़ने और इसे वापस करने के लिए ऐसा कर सकते हैं:

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

@Afreys जवाब से प्रेरित होकर।


जावा 8 में ऐसा करने के लिए एक शानदार तरीका के लिए यहां एक एसएससीसीई है

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);
    }
}

जैसे ही आप कॉल करते contains , containsAll , equals , retainAll , remove , retainAll , size या toArray , आपको वैसे भी तत्वों को पार करना होगा।

यदि आप कभी-कभी केवल कॉलिंग विधियों जैसे कॉलिंग या clear मुझे लगता है कि आप संग्रह को आलसी बनाकर बेहतर होंगे। उदाहरण के लिए आप पहले पुनरावृत्त तत्वों को संग्रहीत करने के लिए एक बैकिंग ArrayList समर्थन कर ArrayList हैं।

मुझे किसी भी पुस्तकालय में ऐसी किसी भी कक्षा के बारे में पता नहीं है, लेकिन यह लिखने के लिए एक काफी सरल अभ्यास होना चाहिए।


दो टिप्पणियां

  1. फोरैच लूप का उपयोग करने के लिए इटेबल टू कलेक्शन को कन्वर्ट करने की कोई ज़रूरत नहीं है - इटरटेबल को ऐसे लूप में सीधे इस्तेमाल किया जा सकता है, इसमें कोई वाक्य रचनात्मक अंतर नहीं है, इसलिए मुझे शायद ही कभी समझ में आया कि मूल सवाल क्यों पूछा गया था।
  2. Iterable संग्रह में कनवर्ट करने का सुझाया गया तरीका असुरक्षित है (यह संग्रहUtils से संबंधित है) - इस बात की कोई गारंटी नहीं है कि अगली () विधि के बाद की कॉल अलग-अलग ऑब्जेक्ट उदाहरण लौटाए। इसके अलावा, यह चिंता शुद्ध सैद्धांतिक नहीं है। जैसे हडोप रेड्यूसर की एक कम विधि को मूल्यों को पारित करने के लिए उपयोग किए जाने वाले इटरटेबल कार्यान्वयन हमेशा अलग-अलग फ़ील्ड मानों के साथ ही वही मान उदाहरण देता है। इसलिए यदि आप उपरोक्त (या CollectionUtils.addAll (Iterator)) से makeCollection लागू करते हैं तो आप सभी समान तत्वों के साथ संग्रह के साथ समाप्त हो जाएंगे।

यदि उपलब्ध हो तो मौजूदा संग्रह को कास्ट करने के लिए मैं अपनी कस्टम उपयोगिता का उपयोग करता हूं।

मुख्य:

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

आदर्श रूप से उपरोक्त इम्यूटेबललिस्ट का उपयोग करेगा, लेकिन अपरिवर्तनीय चयन नल की अनुमति नहीं देता है जो अवांछित परिणाम प्रदान कर सकता है।

टेस्ट:

@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));
}

मैं संग्रह (सेट, सूची, आदि) के सभी उपप्रकारों के लिए समान उपयोगिता लागू करता हूं। मुझे लगता है कि ये पहले से ही अमरूद का हिस्सा होंगे, लेकिन मुझे यह नहीं मिला है।


यह आपके प्रश्न का उत्तर नहीं है लेकिन मेरा मानना ​​है कि यह आपकी समस्या का समाधान है। इंटरफ़ेस org.springframework.data.repository.CrudRepository में वास्तव में विधियां होती हैं जो java.lang.Iterable हैं। java.lang.Iterable लेकिन आपको इस इंटरफ़ेस का उपयोग नहीं करना चाहिए। इसके बजाय उप-इंटरफेस का उपयोग करें, अपने मामले में org.springframework.data.mongodb.repository.MongoRepository । इस इंटरफ़ेस में विधियां हैं जो java.util.List प्रकार की वस्तुएं java.util.List


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());
    }
}

IteratorUtils commons-collections IteratorUtils से उपयोग करता है (हालांकि वे नवीनतम स्थिर संस्करण 3.2.1 में जेनेरिक का समर्थन नहीं करते हैं):

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

संस्करण 4.0 (जो इस समय स्नैपशॉट में है) जेनेरिक का समर्थन करता है और आप @SuppressWarnings छुटकारा पा सकते हैं।

अद्यतन: IterableAsList से IterableAsList की जांच करें।


Guava साथ आप अन्य समान तरीकों के साथ Lists.newArrayList(Iterable) या Sets.newHashSet(Iterable) उपयोग कर सकते हैं। यह निश्चित रूप से सभी तत्वों को स्मृति में कॉपी करेगा। यदि यह स्वीकार्य नहीं है, तो मुझे लगता है कि आपके कोड जो इनके साथ काम करते हैं Iterable Collection बजाय Iterable लेना चाहिए। अमरूद एक Iterable (जैसे Iterables.isEmpty(Iterable) या Iterables.contains(Iterable, Object) ) का उपयोग करके Collection पर कर सकते हैं जो करने के लिए सुविधाजनक तरीकों को प्रदान करने के लिए भी होता है, लेकिन प्रदर्शन प्रभाव अधिक स्पष्ट होते हैं।







collections