2009-11-26 7 views
59

Google संग्रह (अद्यतन: Guava) का उपयोग करते समय मेरे पास कुछ संग्रह हैंडलिंग कोड को सरल बनाने के बारे में एक प्रश्न है।क्या गुवा का उपयोग करके संग्रह को बदलने के दौरान नल को हटाने का कोई शानदार तरीका है?

मुझे "कंप्यूटर" ऑब्जेक्ट्स का एक गुच्छा मिला है, और मैं उनके "संसाधन आईडी" के संग्रह के साथ समाप्त करना चाहता हूं। यह बहुत की तरह किया जाता है:

Collection<Computer> matchingComputers = findComputers(); 
Collection<String> resourceIds = 
    Lists.newArrayList(Iterables.transform(matchingComputers, new Function<Computer, String>() { 
    public String apply(Computer from) { 
     return from.getResourceId(); 
    } 
})); 

अब, getResourceId() वापस आ सकते हैं अशक्त (और बदलते कि एक विकल्प अभी नहीं है), अभी तक इस मामले में मैं जिसके परिणामस्वरूप स्ट्रिंग संग्रह से nulls छोड़ करना चाहते हैं।

Collections2.filter(resourceIds, new Predicate<String>() { 
    @Override 
    public boolean apply(String input) { 
     return input != null; 
    } 
}); 

आप इस तरह एक साथ यह सब डाल सकता है::

यहाँ एक तरह से nulls फिल्टर करने के लिए बाहर है

Collection<String> resourceIds = Collections2.filter(
Lists.newArrayList(Iterables.transform(matchingComputers, new Function<Computer, String>() { 
    public String apply(Computer from) { 
     return from.getResourceId(); 
    } 
})), new Predicate<String>() { 
    @Override 
    public boolean apply(String input) { 
     return input != null; 
    } 
}); 

लेकिन यह शायद ही सुंदर, अकेले पढ़ी जा सकती है, इस तरह के एक सरल कार्य के लिए !

Collection<String> resourceIds = Lists.newArrayList(); 
for (Computer computer : matchingComputers) { 
    String resourceId = computer.getResourceId(); 
    if (resourceId != null) { 
     resourceIds.add(resourceId); 
    } 
} 

एक विकल्प का उपयोग करते हुए ऊपर निश्चित रूप से भी है, लेकिन जिज्ञासा (और अधिक जानने के लिए इच्छा के चलते: वास्तव में, सादे पुराने जावा कोड (कोई फैंसी विधेय या समारोह सामान सब के साथ) यकीनन अधिक स्वच्छ होगा Google संग्रह का), क्या आप Google संग्रह का उपयोग करके कुछ छोटे या अधिक सुरुचिपूर्ण तरीके से एक ही चीज़ कर सकते हैं?

उत्तर

76

वहां पहले से ही Predicates में एक विधेय तुम यहाँ में मदद मिलेगी है - Predicates.notNull() - और आप Iterables.filter() उपयोग कर सकते हैं और इस तथ्य Lists.newArrayList() एक Iterable ले जा सकते हैं कि स्वच्छ यह थोड़ा और ऊपर है।

Collection<String> resourceIds = Lists.newArrayList(
    Iterables.filter(
    Iterables.transform(matchingComputers, yourFunction), 
    Predicates.notNull() 
) 
); 

आप वास्तव में नहीं करते हैं एक Collection की जरूरत है, सिर्फ एक Iterable, तो Lists.newArrayList() कॉल दूर भी जा सकते हैं और आप एक कदम क्लीनर फिर रहे हैं!

मैं आपको पता चल सकता है कि Function फिर से काम में आ जाएगा संदेह है, और जैसा कि

public class Computer { 
    // ... 
    public static Function<Computer, String> TO_ID = ...; 
} 

जो इस अप और भी अधिक साफ (और पुन: उपयोग को बढ़ावा देंगे) सबसे अधिक उपयोगी घोषित किया जाएगा।

+1

नाइस - यह सुनिश्चित नहीं है कि मैंने कभी क्यों नहीं देखा कि भविष्यवाणी विधि पहले ... –

+0

उत्कृष्ट सलाह, धन्यवाद! Predicates.notNull() का उपयोग करना और फ़ंक्शन को स्थिर में रखना वास्तव में कोड को बहुत स्पष्ट करता है। – Jonik

+3

ग्रेट :)। जब मैं एक रूपांतरण के रूप में एक फॉनक्शन का उपयोग करता हूं, तो मुझे इसे एक स्थिर विधि में अलग करना और इसे XXX() में नाम देना पसंद है, मुझे इसे पढ़ने में आसान लगता है। इस मामले में, यह हो सकता है: ट्रांसफॉर्म (मिलान करने वाले, inResourceId())। –

5

सबसे पहले, मैं एक स्थिर फिल्टर कहीं बनाएंगे:

public static final Predicate<Object> NULL_FILTER = new Predicate<Object>() { 
    @Override 
    public boolean apply(Object input) { 
      return input != null; 
    } 
} 

तो आप का उपयोग कर सकते हैं:

Iterable<String> ids = Iterables.transform(matchingComputers, 
    new Function<Computer, String>() { 
     public String apply(Computer from) { 
      return from.getResourceId(); 
     } 
    })); 
Collection<String> resourceIds = Lists.newArrayList(
    Iterables.filter(ids, NULL_FILTER)); 

अपने कोड में हर जगह एक ही नल फिल्टर का उपयोग कर सकते हैं।

आप कहीं और इसी कंप्यूटिंग फ़ंक्शन का उपयोग करें, तो आप कर सकते हैं कि एक निरंतर भी, बस छोड़ने:

Collection<String> resourceIds = Lists.newArrayList(
    Iterables.filter(
     Iterables.transform(matchingComputers, RESOURCE_ID_PROJECTION), 
     NULL_FILTER)); 

यह निश्चित रूप से के रूप में अच्छा के रूप में सी # बराबर होगा नहीं है, लेकिन यह सब होने वाली है एक बहुत बंद और विस्तार तरीकों :) साथ जावा 7 में अच्छे

+5

मैं इसे व्यक्तिगत रूप से NOT_NULL_FILTER कहूंगा। :) और भविष्यवाणी कक्षा में इसके लिए पहले से ही एक स्थिर विधि है (मेरा जवाब देखें)। – Cowan

+1

@Cowan: यह इस बात पर निर्भर करता है कि आप "फ़िल्टर" का इलाज कैसे करते हैं - आप तर्क दे सकते हैं कि यह * आउट * नल को फ़िल्टर करता है। यह नामकरण मोर्चे पर एक सामान्य दर्द है। हालांकि, मुझे लगता है कि यह स्पष्ट है कि यह क्या करने जा रहा है, क्योंकि रिवर्स मूर्खतापूर्ण होगा :) हालांकि भविष्यवाणी विधि पर अच्छी कॉल। –

1

आप अपनी तरह की विधि लिख सकते हैं। यह किसी भी फ़ंक्शन के लिए नल को फ़िल्टर करेगा जो लागू विधि से शून्य लौटाता है।

public static <F, T> Collection<T> transformAndFilterNulls(List<F> fromList, Function<? super F, ? extends T> function) { 
     return Collections2.filter(Lists.transform(fromList, function), Predicates.<T>notNull()); 
    } 

विधि को निम्नलिखित कोड के साथ बुलाया जा सकता है।

Collection c = transformAndFilterNulls(Lists.newArrayList("", "SD", "DDF"), new Function<String, Long>() { 

    @Override 
    public Long apply(String s) { 
     return s.isEmpty() ? 20L : null; 
    } 
}); 
System.err.println(c); 
33

साथ FluentIterable (अमरूद 12 के बाद से) थोड़ा "खूबसूरत" वाक्य रचना:

ImmutableList<String> resourceIds = FluentIterable.from(matchingComputers) 
    .transform(getResourceId) 
    .filter(Predicates.notNull()) 
    .toList(); 

static final Function<Computer, String> getResourceId = 
    new Function<Computer, String>() { 
     @Override 
     public String apply(Computer computer) { 
      return computer.getResourceId(); 
     } 
    }; 

ध्यान दें कि लौटे सूची एक ImmutableList है। हालांकि, आप तत्वों को मनमाने ढंग से संग्रह में डालने के लिए copyInto() विधि का उपयोग कर सकते हैं।

13

यह @Jon Skeet expected से अधिक समय लगा, लेकिन जावा 8 धाराओं इस सरल बनाने के कार्य करें:

List<String> resourceIds = computers.stream() 
    .map(Computer::getResourceId) 
    .filter(Objects::nonNull) 
    .collect(Collectors.toList()); 

तुम भी .filter(x -> x != null) उपयोग कर सकते हैं यदि आप चाहें, the difference is very minor

+0

मैं Java8 के प्राइवेट्स # नॉट() 'के बराबर जावा 8 खोज रहा था। 'ऑब्जेक्ट्स' –

+0

को देखने का कभी सोचा नहीं है यहां एपीआई दस्तावेज़ है: https://docs.oracle.com/javase/8/docs/api/java/util/Objects.html#nonNull-java.lang.Object- – amoebe

संबंधित मुद्दे

 संबंधित मुद्दे