Java 8(or 17) 로 이루어진 프로젝트를 진행 중 Stream API의 allMatch 메서드에서 이상한 점을 발견했습니다.
Empty Collection에 allMatch를 수행했더니, Predicate가 적용될 요소가 없어서 False가 나올 줄 알았으나 True를 반환하는 것이었습니다.
어떻게 된 상황인지 Stream API 코드를 살펴보기로 했습니다.
테스트 코드입니다.
@Test
public void test(){
List<Integer> list = Arrays.asList();
final boolean isResult = list.stream().allMatch(e -> e >= 2);
assertFalse(isResult);
}
스택트레이스입니다.
tryAdvance:1003, Spliterators$ArraySpliterator (java.util)
forEachWithCancel:129, ReferencePipeline (java.util.stream)
copyIntoWithCancel:527, AbstractPipeline (java.util.stream)
copyInto:513, AbstractPipeline (java.util.stream)
wrapAndCopyInto:499, AbstractPipeline (java.util.stream)
evaluateSequential:230, MatchOps$MatchOp (java.util.stream)
evaluateSequential:196, MatchOps$MatchOp (java.util.stream)
evaluate:234, AbstractPipeline (java.util.stream)
allMatch:637, ReferencePipeline (java.util.stream)
test:16, StreamTest (com.board.infrastructure.java)
해당 코드는 다음과 같습니다.
Spliterator의 tryAdvance 메서드 안에서 index >= 0 && index < fence 조건식에 따라 빈 컬렉션의 경우 false를 반환합니다.
하지만 MatchOps의 evaluateSequential 메서드의 다음 영역에서 true를 반환합니다.
이 helper.wrapAndCopyInto의 반환형은 Sink 인터페이스의 구체형 중 BooleanTerminalSink 입니다.
코드를 보면 다음과 같습니다.
getAndClearState() 에서 true를 반환하다 보니 최종 결과가 true가 된 것이었습니다.
그러면 언제 객체가 생성되고 그 때 왜 true가 value에 셋팅되는지 알아야 되겠는데요.
allMatch 메서드를 호출하면 MatchOps.makeRef 를 통해 TerminalOp가 생성되는데 이 때 파라미터로 전달되는 MatchOps.MatchKind.ALL의 shortCircuitResult 가 false입니다.
따라서 결과가 true 였던 것입니다.
그러면 요소가 있는 컬렉션이라면 이 값이 바뀔까요?
최종 결과가 false를 반환하도록 테스트 코드를 작성하고 디버깅을 해봤습니다.
수정된 테스트 코드에서 컬렉션 부분만 수정했습니다.
List<Integer> list = Arrays.asList(1, 2, 3);
final boolean isResult = list.stream().allMatch(e -> e >= 2);
assertFalse(isResult);
이렇게 코드가 수행되면 아래 Spliterator.tryAdvance에서 action.accept(e)가 호출됩니다.
그 후 아래 코드에서 처럼 Sink 객체의 value 값을 변경합니다.
디버깅이 힘들긴 하지만 allMatch에 대해서 조금 더 자세히 알게 되었습니다.
'[개발] 언어 > Java' 카테고리의 다른 글
Java Stream API의 patitioningBy에 대해서 알아보자. (0) | 2024.11.14 |
---|---|
Java 8 Parallel Stream (0) | 2024.09.19 |
Java Method (1) | 2023.11.11 |
Java Switch Case (0) | 2023.11.09 |
SOLID (1) | 2023.10.30 |