मानों को तभी फ़िल्टर करें जब Java8 में लैम्ब्डा का उपयोग न करें


160

मेरे पास कहने के लिए वस्तुओं की एक सूची है car। मैं जावा 8 का उपयोग करते हुए कुछ पैरामीटर के आधार पर इस सूची को फ़िल्टर करना चाहता हूं। लेकिन अगर पैरामीटर है null, तो यह फेंकता है NullPointerException। शून्य मान कैसे फ़िल्टर करें?

वर्तमान कोड इस प्रकार है

requiredCars = cars.stream().filter(c -> c.getName().startsWith("M"));

यह NullPointerExceptionअगर getName()रिटर्न देता है null


क्या आप केवल "शून्य मान नहीं तो फ़िल्टर मान" या "शून्य मान फ़िल्टर करना" चाहते हैं? जो मुझे विरोधाभासी लगता है।
होल्गर

3
क्या मैं सुझाव दे सकता हूं कि आप तुनकी के जवाब को स्वीकार करते हैं क्योंकि यह केवल वही प्रतीत होता है जो वास्तव में आपके प्रश्न का उत्तर देता है।
मार्क बूथ

जवाबों:


322

इस विशेष उदाहरण में मुझे लगता है कि @Tagir 100% सही है इसे एक फिल्टर में प्राप्त करें और दो चेक करें। मैं Optional.ofNullableवैकल्पिक सामान का उपयोग नहीं करूंगा वास्तव में वापसी प्रकार के लिए तर्क नहीं करना चाहिए ... लेकिन वास्तव में न तो यहां और न ही वहां।

मैं इंगित करना चाहता था कि java.util.Objectsएक व्यापक मामले में इसके लिए एक अच्छी विधि है, इसलिए आप ऐसा कर सकते हैं:

cars.stream()
    .filter(Objects::nonNull)

जो आपकी अशक्त वस्तुओं को हटा देगा। किसी परिचित के लिए नहीं, यह निम्न के लिए छोटा हाथ है:

cars.stream()
    .filter(car -> Objects.nonNull(car))

आंशिक रूप से शुरू होने वाले कार नामों की सूची को वापस करने के लिए प्रश्न का उत्तर दें "M":

cars.stream()
    .filter(car -> Objects.nonNull(car))
    .map(car -> car.getName())
    .filter(carName -> Objects.nonNull(carName))
    .filter(carName -> carName.startsWith("M"))
    .collect(Collectors.toList());

एक बार जब आप शॉर्टहैंड लैम्ब्डा के लिए अभ्यस्त हो जाते हैं, तो आप यह भी कर सकते हैं:

cars.stream()
    .filter(Objects::nonNull)
    .map(Car::getName)        // Assume the class name for car is Car
    .filter(Objects::nonNull)
    .filter(carName -> carName.startsWith("M"))
    .collect(Collectors.toList());

दुर्भाग्य से एक बार जब .map(Car::getName)आप केवल कारों की नहीं बल्कि नामों की सूची लौटाएंगे। इतना कम सुंदर लेकिन पूरी तरह से सवाल का जवाब देता है:

cars.stream()
    .filter(car -> Objects.nonNull(car))
    .filter(car -> Objects.nonNull(car.getName()))
    .filter(car -> car.getName().startsWith("M"))
    .collect(Collectors.toList());

1
ध्यान दें कि अशक्त कार समस्या नहीं है। इस मामले में, यह समस्या पैदा करने वाली संपत्ति का नाम है। तो Objects::nonNullयहाँ इस्तेमाल नहीं किया जा सकता है, और अंतिम सलाह में cars.stream() .filter(car -> Objects.nonNull(car.getName()))मेरा मानना ​​है कि
kiedysktos

1
BTW, मुझे लगता है कि cars.stream() .filter(car -> Objects.nonNull(car.getName()) && car.getName().startsWith("M"))इस प्रश्न के संदर्भ में आपकी सलाह का सारांश होगा
kiedysktos

3
@kiedysktos यह एक अच्छी बात है कि कॉल करने से .startWithअशक्त सूचक भी हो सकता है। मैं जिस बिंदु को बनाने की कोशिश कर रहा था वह यह है कि जावा विशेष रूप से आपकी धाराओं से अशक्त वस्तुओं को छानने के लिए एक विधि की आपूर्ति करता है।
xbakesx

@ मार्क बूथ हाँ, स्पष्ट रूप Objects.nonNullसे इसके बराबर है != null, आपका विकल्प छोटा है
kiedysktos

1
क्या आप कार के नाम ( String) की जगह कारों की सूची नहीं बना रहे हैं Car?
user1803551

59

आपको बस उन कारों को फ़िल्टर करने की आवश्यकता है जिनका एक nullनाम है:

requiredCars = cars.stream()
                   .filter(c -> c.getName() != null)
                   .filter(c -> c.getName().startsWith("M"));

3
यह एक वास्तविक शर्म की बात है कि यह उत्तर अधिक उच्च मतदान नहीं है क्योंकि यह एकमात्र ऐसा उत्तर प्रतीत होता है जो वास्तव में प्रश्न का उत्तर देता है।
मार्क बूथ

@MarkBooth सवाल "शून्य मान कैसे फ़िल्टर करें?" लगता है कि xbakesx द्वारा अच्छी तरह से उत्तर दिया जा रहा है।
vegemite4me

@MarkBooth आप सही हैं तारीखों को देखते हुए। मेरी गलती।
vegemite4me

प्रदर्शन के लिहाज से दो बार धारा को छानना अच्छा है या बेहतर है कि छानने के लिए विधेय का उपयोग करें? सिर्फ जानना चाहता हूँ।
वैभव_शर्मा २

51

प्रस्तावित उत्तर बहुत अच्छे हैं। बस का उपयोग कर अशक्त सूची के मामले को संभालने के लिए एक सुधार का सुझाव देना चाहते हैं Optional.ofNullable, जावा 8 में नई सुविधा :

 List<String> carsFiltered = Optional.ofNullable(cars)
                .orElseGet(Collections::emptyList)
                .stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

तो, पूरा जवाब होगा:

 List<String> carsFiltered = Optional.ofNullable(cars)
                .orElseGet(Collections::emptyList)
                .stream()
                .filter(Objects::nonNull) //filtering car object that are null
                .map(Car::getName) //now it's a stream of Strings
                .filter(Objects::nonNull) //filtering null in Strings
                .filter(name -> name.startsWith("M"))
                .collect(Collectors.toList()); //back to List of Strings

5
वैकल्पिक का बुरा उपयोग। रिक्त स्थान में रिक्त संग्रह के पर्याय के रूप में नल का उपयोग कभी नहीं किया जाना चाहिए।
वीजीआर

4
@VGR बेशक, लेकिन व्यवहार में ऐसा नहीं है। कभी-कभी (ज्यादातर समय) आपको कोड के साथ काम करने की आवश्यकता होती है जो बहुत सारे लोगों ने काम किया। कभी-कभी आप बाहरी इंटरफेस से अपना डेटा प्राप्त करते हैं। उन सभी मामलों के लिए, वैकल्पिक एक महान उपयोग है।
जॉनी

1
ध्यान दें कि अशक्त कार समस्या नहीं है। इस मामले में, यह समस्या पैदा करने वाली संपत्ति का नाम है। इसलिए Objects::nonNullसमस्या का समाधान नहीं किया जाता है क्योंकि गैर-शून्य कार का नाम == null
kiedysktos

बेशक @kiedysktos, लेकिन यह वह नहीं है जो मैं उत्तर में दिखाना चाहता था। लेकिन, मैं स्वीकार कर रहा हूं कि आप क्या कह रहे हैं और उत्तर का संपादन कर रहे हैं :)
जॉनी

24

आप इसे एकल फ़िल्टर चरण में कर सकते हैं:

requiredCars = cars.stream().filter(c -> c.getName() != null && c.getName().startsWith("M"));

यदि आप getName()कई बार कॉल नहीं करना चाहते हैं (उदाहरण के लिए, यह महंगी कॉल है), तो आप यह कर सकते हैं:

requiredCars = cars.stream().filter(c -> {
    String name = c.getName();
    return name != null && name.startsWith("M");
});

या अधिक परिष्कृत तरीके से:

requiredCars = cars.stream().filter(c -> 
    Optional.ofNullable(c.getName()).filter(name -> name.startsWith("M")).isPresent());

दूसरे उदाहरण में इनलाइन विस्तार मेरे उपयोग के मामले के लिए मूल्यवान था
पॉल

3

की शक्ति का लाभ java.util.Optional#map():

List<Car> requiredCars = cars.stream()
  .filter (car -> 
    Optional.ofNullable(car)
      .map(Car::getName)
      .map(name -> name.startsWith("M"))
      .orElse(false) // what to do if either car or getName() yields null? false will filter out the element
    )
  .collect(Collectors.toList())
;

1

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

List<Car> requiredCars = cars.stream()
    .filter (t->  t!= null && StringUtils.startsWith(t.getName(),"M"))
    .collect(Collectors.toList());
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.