धाराओं के साथ अपवादों को संभालना


10

मेरे पास एक है Map<String,List<String>>और इसे चालू करना चाहता हूं Map<String,List<Long>>क्योंकि Stringसूची में प्रत्येक का प्रतिनिधित्व करता है Long:

Map<String,List<String>> input = ...;
Map<String,List<Long>> output= 
input.entrySet()
       .stream()
       .collect(toMap(Entry::getKey, e -> e.getValue().stream()
                                                      .map(Long::valueOf)
                                                      .collect(toList()))
               );

मेरा मुख्य मुद्दा यह है कि प्रत्येक Stringसही ढंग से प्रतिनिधित्व नहीं कर सकता है Long; कुछ समस्या हो सकती है। Long::valueOfअपवाद बढ़ा सकते हैं। यदि यह मामला है, तो मैं एक अशक्त या खाली लौटना चाहता हूंMap<String,List<Long>>

क्योंकि मैं इस outputनक्शे के बाद पुनरावृति करना चाहता हूं । लेकिन मैं किसी भी त्रुटि रूपांतरण को स्वीकार नहीं कर सकता; एक भी नहीं। किसी भी विचार के रूप में कि मैं गलत स्ट्रिंग के मामले में खाली आउटपुट कैसे लौटा सकता हूं -> लंबा रूपांतरण?


मैं नमन समाधान से सहमत हूं, लेकिन दुर्भाग्य से कैच ब्लॉक में, मैं कुंजी (एंट्री :: getKey) प्राप्त करने में विफल रहा हूं, जिसके लिए स्ट्रिंग -> लंबा रूपांतरण गलत है
एंटोनबोर्फ

इसी तरह की चर्चा यहां: स्ट्रिंग के लिए - संभावना है कि खराब डेटा को अपवादों से बचने की जरूरत है, जहां मैंने अंततः regex के साथ पूर्व-जांच करने का फैसला किया (पार्सलॉन्ग डॉक्स एक ही पार्सिंग नियमों का उपयोग करते हैं और आप शायद परिणाम वापस LongStreamकरने की योजना बनाना चाहते हैंempty
AjahnCharles

माफ़ कीजिए मैंने गलत समझा। मैंने सोचा कि आप खाली / अशक्त के रूप में एक भी प्रविष्टि वापस करने का मतलब है; लेकिन अब मुझे लगता है कि आप पूरे नक्शे का मतलब!
AjnnCharles

1
यह पूरी तरह से स्पष्ट नहीं है कि मुख्य बिंदु क्या है - आप त्रुटि के मामले में एक खाली नक्शा वापस करना चाहते हैं, लेकिन फिर भी "कुंजी" प्रिंट करें जहां त्रुटि कंसोल पर दिखाई दी? मेरा मतलब है, संदर्भ में, जहां अपवाद दिखाई दिया आमतौर पर कॉल स्टैक अप ले जाया जाता है के बारे में जानकारी में अपवाद। इसके बावजूद: आपने विशेष रूप से धाराओं के बारे में पूछा था, लेकिन मैं नेस्टेड "कलेक्ट" कॉल से बचने की जोरदार सिफारिश करूंगा । जिन लोगों को बाद में बनाए रखना है (और यह आपके भविष्य के लिए अच्छा हो सकता है !) आश्चर्य होगा कि एच क्या है ... आपने वहां किया। कम से कम कुछ ठीक से नामित सहायक विधियों का परिचय दें।
मार्को 13

जवाबों:


4

catchअपवाद पर एक स्पष्ट के बारे में कैसे :

private Map<String, List<Long>> transformInput(Map<String, List<String>> input) {
    try {
        return input.entrySet()
                .stream()
                .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().stream()
                        .map(Long::valueOf)
                        .collect(Collectors.toList())));
    } catch (NumberFormatException nfe) {
        // log the cause
        return Collections.emptyMap();
    }
}

ok अच्छा लगता है ... लेकिन कैच (nfe) में मैं कुंजी के विशिष्ट मान (Entry :: getKey) और गलत स्ट्रिंग को पुनः प्राप्त करना चाहूंगा जिसके लिए यह विफल हो जाता है इसलिए मैं ठीक से लॉग इन कर सकता हूं जहां यह गलत हो जाता है। क्या यह संभव है ?
एंटोनबोर्फ

@AntonBoarf यदि आप बस कुंजी को लॉग इन करना चाहते हैं, जिसके लिए यह स्ट्रिंग पार्स करने में विफल रहा है, तो उपयोग करेंnfe.getMessage()
नमन

1
@AntonBoarf अपवाद के संदेश में विकृत इनपुट स्ट्रिंग शामिल होगी। जिम्मेदार कुंजी प्राप्त करने के लिए, मैं एक स्पष्ट खोज करूँगा, केवल जब अपवाद हुआ, जैसेinput.entrySet().stream() .filter(e -> e.getValue().stream().anyMatch(s -> !new Scanner(s).hasNextLong())) .map(Map.Entry::getKey) .findAny()
Holger

@धारक। धन्यवाद ... यह जटिल लगता है ... मैं सोच रहा था कि अगर लूप जावा 5 के लिए फॉक्स का उपयोग करना मेरे मामले में बेहतर नहीं है
एंटोनबॉर्फ

@AntonBoarf बस दोनों को लागू करें और तुलना करें ...
Holger

3

मैं व्यक्तिगत रूप से Optionalनंबर पार्सिंग के आसपास एक इनपुट प्रदान करना चाहता हूं :

public static Optional<Long> parseLong(String input) {
    try {
        return Optional.of(Long.parseLong(input));
    } catch (NumberFormatException ex) {
        return Optional.empty();
    }
}

फिर, अपने स्वयं के कोड का उपयोग करना (और खराब इनपुट को अनदेखा करना ):

Map<String,List<String>> input = ...;
Map<String,List<Long>> output= 
input.entrySet()
       .stream()
       .collect(toMap(Entry::getKey, e -> e.getValue().stream()
                                                      .map(MyClass::parseLong)
                                                      .filter(Optional::isPresent)
                                                      .map(Optional::get)
                                                      .collect(toList()))
               );

इसके अतिरिक्त, इसे और अधिक सफल बनाने के लिए एक सहायक विधि पर विचार करें:

public static List<Long> convertList(List<String> input) {
    return input.stream()
        .map(MyClass::parseLong).filter(Optional::isPresent).map(Optional::get)
        .collect(Collectors.toList());
}

public static List<Long> convertEntry(Map.Entry<String, List<String>> entry) {
    return MyClass.convertList(entry.getValue());
}

फिर आप अपने स्ट्रीम के कलेक्टर में परिणाम फ़िल्टर कर सकते हैं:

Map<String, List<Long>> converted = input.entrySet().stream()
    .collect(Collectors.toMap(Entry::getKey, MyClass::convertEntry));

आप Optionalअपनी सूचियों में खाली वस्तुओं को भी रख सकते हैं , और फिर मूल के साथ नए List<Optional<Long>>(इसके बजाय List<Long>) में उनके सूचकांक की तुलना करके List<String>, आप उस स्ट्रिंग को पा सकते हैं जो किसी भी गलत इनपुट के कारण हुआ था। आप बस इन विफलताओं को भी लॉग इन कर सकते हैंMyClass#parseLong

हालाँकि, यदि आपकी इच्छा किसी बुरे इनपुट पर काम नहीं करने की है , तो आप जिसे पकड़ने की कोशिश कर रहे हैं, उसके अनुसार पूरी धारा को घेरते हुए (नमन के जवाब के अनुसार) वह रास्ता है जो मैं ले जाऊंगा।


2

आप StringBuilderअपवाद के लिए कुंजी बना सकते हैं और जांच सकते हैं कि eleक्या नीचे के रूप में संख्यात्मक है,

 public static Map<String, List<Long>> transformInput(Map<String, List<String>> input) {
    StringBuilder sb = new StringBuilder();
    try {
    return input.entrySet()
            .stream()
            .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().stream()
                    .map(ele->{
                        if (!StringUtils.isNumeric(ele)) {
                            sb.append(e.getKey()); //add exception key
                            throw new NumberFormatException();
                        }
                        return Long.valueOf(ele);
                    })
                    .collect(Collectors.toList())));
} catch (NumberFormatException nfe) {
    System.out.println("Exception key "+sb);
    return Collections.emptyMap();
}
}

आशा है ये मदद करेगा।


0

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

// StringUtils.java
public static boolean isNumeric(String string) {
    try {
        Long.parseLong(string);
        return true;
    } catch(NumberFormatException e) {
        return false;
    }
}

यह सब कुछ ध्यान रखेगा।

और इसे अपनी स्ट्रीम में इस्तेमाल करें।

Map<String, List<Long>> newMap = map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> mapToLongValues(entry.getValue())));

public List<Long> mapToLongValues(List<String> strs) {
    return strs.stream()
        .filter(Objects::nonNull)
        .filter(StringUtils::isNumeric)
        .map(Long::valueOf)
        .collect(Collectors.toList());
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.