JShell은 Java 9부터 도입된 대화형(인터랙티브) 도구로, 간단한 문장이나 표현식을 입력으로 받아 즉시 평가하고 그 결과를 바로 화면에 출력해 줍니다. 별도의 클래스 파일 작성이나 컴파일 과정 없이 코드를 실험할 수 있어 학습과 프로토타이핑에 매우 유용합니다.
터미널 연산(Terminal Operation)이란?
터미널 연산은 스트림을 입력으로 받아 새로운 출력 스트림을 반환하지 않는 스트림 연산을 의미합니다. 터미널 연산이 실행되는 순간 스트림 파이프라인이 최종 처리되며, 그 결과로 단일 값을 반환합니다. 반환되는 값은 하나의 기본 타입 값 또는 객체일 수도 있고, 객체 컬렉션일 수도 있습니다.
대표적인 터미널 연산 메서드로는 reduce(), max(), min(), forEach(), collect() 등이 있습니다.
아래 코드 예제에서는 JShell 환경에서 다양한 터미널 연산(min(), max(), reduce())을 실제로 사용하는 방법을 확인할 수 있습니다.
JShell 실습 예제
jshell> IntStream.range(1, 11).reduce(0, (n1, n2) -> n1 + n2);
$1 ==> 55
jshell> List.of(23, 12, 34, 53).stream().max();
| Error:
| method max in interface java.util.stream.Stream cannot be applied to given types;
| required: java.util.Comparator<? super java.lang.Integer>
| found: no arguments
| reason: actual and formal argument lists differ in length
| List.of(23, 12, 34, 53).stream().max();
| ^----------------------------------^
jshell> List.of(23, 12, 34, 53).stream().max((n1, n2) -> Integer.compare(n1, n2));
$2 ==> Optional[53]
jshell> $2.isPresent()
$3 ==> true
jshell> List.of(23, 12, 34, 53).stream().max((n1, n2) -> Integer.compare(n1, n2)).get();
$4 ==> 53
jshell> List.of(23, 12, 34, 53).stream().filter(e -> e%2==1).forEach(e -> System.out.println(e))
23
53
jshell> List.of(23, 12, 34, 53).stream().filter(e -> e%2==1).collect(Collectors.toList());
$6 ==> [23, 53]
jshell> List.of(23, 12, 34, 53).stream().min((n1, n2) -> Integer.compare(n1, n2)).get();
$8 ==> 12코드 설명
1. reduce()로 합계 구하기
IntStream.range(1, 11)은 1부터 10까지의 정수 스트림을 생성합니다. 여기에 reduce(0, (n1, n2) -> n1 + n2)를 적용하면 초기값 0부터 시작해 모든 요소를 더한 55가 반환됩니다. reduce()는 누적 함수를 통해 스트림 전체를 하나의 값으로 축소하는 대표적인 터미널 연산입니다.
2. max() 호출 시 주의사항
max() 메서드는 인수 없이 호출하면 컴파일 오류가 발생합니다. 반드시 Comparator를 인수로 전달해야 하며, 위 예제에서는 람다 표현식 (n1, n2) -> Integer.compare(n1, n2)를 사용해 비교 기준을 지정했습니다. 결과는 Optional[53] 형태로 반환됩니다.
3. Optional 처리하기
max()와 min()은 스트림이 비어 있을 가능성을 고려해 Optional 객체를 반환합니다. isPresent()로 값의 존재 여부를 확인한 후, get() 메서드로 실제 값을 꺼낼 수 있습니다. 안전한 코드를 위해서는 get()보다 orElse()나 ifPresent()를 사용하는 것이 권장됩니다.
4. filter()와 forEach(), collect() 조합
filter(e -> e%2==1)은 홀수만 걸러내는 중간 연산입니다. 이후 forEach()로 각 요소를 출력하거나, collect(Collectors.toList())로 결과를 리스트([23, 53])로 수집할 수 있습니다.
5. min()으로 최솟값 구하기
max()와 동일한 방식으로 Comparator를 전달하여 min()을 호출하면, 리스트에서 가장 작은 값인 12를 얻을 수 있습니다.
정리
JShell을 활용하면 스트림 API의 터미널 연산을 한 줄씩 즉시 테스트해 볼 수 있습니다. reduce()는 스트림을 단일 값으로 축소하고, max()/min()은 Comparator를 인수로 받아 Optional 형태의 최댓값·최솟값을 반환한다는 점을 기억하면 됩니다. 이러한 대화형 실습은 스트림 개념을 익히는 데 큰 도움이 됩니다.