스트림으로 예외 처리


10

나는 목록에있는 각각 이 다음을 나타 내기 때문에 Map<String,List<String>>로 바꾸고 싶다 .Map<String,List<Long>>StringLong

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예외가 발생할 수 있습니다. 이 경우 null 또는 빈 값을 반환하고 싶습니다.Map<String,List<Long>>

이지도 위에서 반복하고 싶기 때문 output입니다. 그러나 오류 변환을 받아 들일 수 없습니다. 단 하나도 아닙니다. 잘못된 문자열-> 긴 변환의 경우 빈 출력을 반환하는 방법에 대한 아이디어가 있습니까?


Naman 솔루션에 동의하지만 불행히도 catch 블록에서 String-> Long conversion이 잘못된 키 (Entry :: getKey)를 검색하지 못합니다.
AntonBoarf

비슷한 토론 : String to int-아마도 나쁜 데이터 는 정규식으로 사전 확인하기로 결정한 예외를 피해야합니다 (parseLong 문서는 동일한 구문 분석 규칙을 사용하고 결과 LongStream를 제거하려는 경우 아마도 반환하려고 empty합니다)
AjahnCharles

미안, 오해 했어 나는 당신이 하나의 항목을 비우거나 null로 반환해야한다고 생각했다. 하지만 이제는 전체지도를 의미한다고 생각합니다!
AjahnCharles

1
요점이 무엇인지 완전히 명확하지는 않습니다. 오류가 발생한 경우 빈 맵을 반환하려고하지만 오류가 콘솔에 나타난 "키"를 여전히 인쇄 하시겠습니까? 내가 등장을 제외하고는 일반적으로 호출 스택을 수송하는 컨텍스트에 대한 정보는 의미 에서 예외를. 에 관계없이 그 : 당신은 특별히 스트림에 대해 질문,하지만 난 거라고 강하게 중첩 "수집"전화를하지 않도록하는 것이 좋습니다. 나중에 그것을 유지해야하는 사람들은 (그리고 이것이 당신에게 미래 일지도 모른다 !) 당신이 거기서 무엇을했는지 궁금 할 것이다. 적어도 적절하게 이름이 지정된 헬퍼 메소드를 도입하십시오.
Marco13

답변:


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는 좋아 보이지만 catch (nfe)에서 키의 특정 값 (Entry :: getKey)과 잘못된 String을 검색하여 오류가 발생한 위치를 정확하게 기록 할 수 있습니다. 가능합니까?
AntonBoarf 19

@AntonBoarf 문자열을 구문 분석하지 못한 키만 기록하려면nfe.getMessage()
Naman

1
@AntonBoarf 예외 메시지는 잘못된 입력 문자열을 포함합니다. 책임있는 키를 얻으려면 예외가 발생한 경우에만 명시 적 검색을 수행합니다 (예input.entrySet().stream() .filter(e -> e.getValue().stream().anyMatch(s -> !new Scanner(s).hasNextLong())) .map(Map.Entry::getKey) .findAny()
Holger

@보유자. 덕분에 ... 그 복잡 보인다 ... 루프 Java5에 대한 STANDART를 사용하는 경우 궁금 해요되어 있지 나은 내 경우
AntonBoarf

@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예외를 위해 for 키를 만들고 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

문자열에서 숫자를 확인하고 스트림에서 숫자를 필터링하고 null 값을 필터링하여 맵에 수집하는 도우미 메서드를 작성할 수 있습니다.

// 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());
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.