스트림으로 예외 처리


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.