Java에서 객체 리스트를 다루다 보면 숫자들 중 가장 큰 값과 가장 작은 값을 찾는 일이 자주 있습니다. 이때 Java Stream을 사용하면 반복문을 길게 쓰지 않고도 깔끔하게 처리할 수 있습니다. 이번 글에서는 정수 리스트에서 max(), min() 메서드를 이용해 최댓값과 최솟값을 구하는 실습을 해보겠습니다.
—

문제: 정수 리스트에서 최댓값과 최솟값 구하기
주어진 정수 리스트에서 가장 큰 값과 가장 작은 값을 찾습니다.
—
데이터
[45, 23, 78, 12, 56, 89, 34, 67]
—
요구사항
max(),min()메서드 사용OptionalInt반환값 처리- 최댓값과 최솟값 출력
—
전체 소스 코드
코드 자체는 정상 동작하므로, 가독성만 정리한 버전으로 보시면 됩니다.
import java.util.Arrays;
import java.util.List;
public class StreamMaxMin {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(45, 23, 78, 12, 56, 89, 34, 67);
System.out.println("숫자 리스트: " + numbers);
int max = numbers.stream()
.mapToInt(Integer::intValue)
.max()
.orElse(0);
int min = numbers.stream()
.mapToInt(Integer::intValue)
.min()
.orElse(0);
System.out.println("최댓값: " + max);
System.out.println("최솟값: " + min);
}
}
—
핵심 코드 설명
1) numbers.stream()
numbers.stream()
List<Integer>를 Stream으로 바꿉니다. 즉, 리스트 안의 데이터를 연속적으로 처리할 수 있는 흐름으로 만들어 줍니다.
Java Stream을 처음 배우는 분들은 “리스트를 바로 처리하는 도구” 정도로 이해하면 좋습니다.
—
2) mapToInt(Integer::intValue)
.mapToInt(Integer::intValue)
이 부분이 초보자에게 가장 헷갈릴 수 있습니다.
numbers는Integer객체들의 리스트입니다.- 그런데
max()와min()을 더 편하게 쓰려면int형태로 바꾸는 것이 좋습니다. - 그래서
mapToInt()를 사용해IntStream으로 변환합니다.
Integer::intValue는?
메서드 참조입니다. 각 Integer 객체에서 실제 정수값을 꺼내는 역할을 합니다.
즉, 아래 람다식과 거의 같은 뜻입니다.
.mapToInt(x -> x.intValue())
초보자 입장에서는 “객체를 기본형 int로 바꿔준다”고 기억하면 충분합니다.
—
3) max()와 min()
.max()
.min()
IntStream에서 최댓값과 최솟값을 찾습니다.
여기서 중요한 점은 결과가 바로 int가 아니라 OptionalInt라는 점입니다. 왜냐하면 스트림이 비어 있을 수도 있기 때문입니다.
예를 들어 리스트가 비어 있다면 최댓값이나 최솟값이 존재하지 않으므로, 안전하게 처리해야 합니다. 이런 이유로 Java Stream은 결과를 바로 숫자로 주지 않고, OptionalInt로 감싸서 돌려줍니다.
—
4) orElse(0)
.orElse(0)
OptionalInt 값이 있으면 그 값을 꺼내고, 없으면 0을 반환합니다.
즉:
- 값이 있으면 그 값 사용
- 값이 없으면 0 사용
이번 문제처럼 데이터가 반드시 들어 있는 경우에도, OptionalInt 처리를 익혀 두는 것이 중요합니다. 실무에서도 Java Stream 결과를 다룰 때 자주 쓰는 패턴입니다.
—
실행 결과
숫자 리스트: [45, 23, 78, 12, 56, 89, 34, 67]
최댓값: 89
최솟값: 12
—
초보자가 자주 헷갈리는 부분
1) max()와 min()은 왜 int가 아니라 OptionalInt를 반환하나요?
스트림이 비어 있을 수 있기 때문입니다. 값이 없는데 억지로 숫자를 반환하면 오류가 생길 수 있어서, Java는 OptionalInt로 안전하게 감싸서 돌려줍니다.
—
2) mapToInt()는 꼭 써야 하나요?
이 문제에서는 정수 리스트이므로 IntStream으로 바꾸는 것이 가장 간단합니다. 만약 List<Integer>에서 바로 처리하려고 하면, 객체와 기본형 사이의 차이 때문에 코드가 덜 직관적일 수 있습니다.
—
3) Integer::intValue가 어려워요.
메서드 참조는 처음 보면 낯설 수 있습니다. 하지만 의미는 단순합니다.
Integer객체에서- 실제
int값을 꺼내는 것
처음에는 람다식으로 바꿔 생각해도 괜찮습니다.
.mapToInt(x -> x.intValue())
—
4) orElse(0)의 0은 무조건 맞나요?
항상 그런 것은 아닙니다. 리스트가 비어 있을 가능성이 있고, 기본값으로 0이 적절하지 않다면 다른 값을 넣어야 합니다. 즉, orElse(0)은 예시용 안전값이라고 생각하면 좋습니다.
—
직접 연습해 볼 과제
과제 1
리스트의 최댓값과 최솟값뿐 아니라 합계도 구해 보세요.
힌트: sum() 메서드를 사용하면 됩니다.
—
과제 2
데이터를 아래처럼 바꿔서 다시 실행해 보세요.
[5, 5, 10, 20, 3, 50, 1]
최댓값과 최솟값이 어떻게 바뀌는지 확인해 보세요.
—
과제 3
리스트가 비어 있을 때도 동작하도록 바꿔 보세요.
List<Integer> numbers = Arrays.asList();
이때 orElse(0)이 어떤 역할을 하는지 직접 확인할 수 있습니다.
—
자주 묻는 질문
Q1. Stream과 IntStream은 무엇이 다른가요?
Stream<Integer>는 객체 중심 스트림이고, IntStream은 int 같은 기본형 전용 스트림입니다. 숫자 계산에서는 IntStream이 더 편하고 효율적인 경우가 많습니다.
—
Q2. max()와 min()을 반복문으로 쓰는 것보다 Stream이 좋은가요?
상황에 따라 다르지만, 코드가 짧고 읽기 쉬운 장점이 있습니다. 특히 Java Stream을 사용하면 필터, 변환, 집계가 한 흐름으로 이어져 실습하기 좋습니다.
—
Q3. orElse(0) 대신 getAsInt()를 쓰면 안 되나요?
쓸 수는 있지만, 스트림이 비어 있을 때 예외가 발생할 수 있습니다. 안전하게 처리하려면 보통 orElse(0)을 더 많이 사용합니다.
—
Q4. List<Integer>에서 바로 max()를 사용할 수 있나요?
그대로는 어렵고, 보통 stream()으로 변환한 뒤 mapToInt()를 사용합니다. 즉, 객체 리스트를 숫자 계산에 맞게 바꿔주는 과정이 필요합니다.
—
개념 정리
- Java Stream은 데이터를 순차적으로 처리하는 도구입니다.
- 객체 리스트를 숫자 계산에 쓰려면
mapToInt()로IntStream으로 바꾸는 것이 편합니다. max(),min()은 결과를OptionalInt로 반환하므로orElse()로 안전하게 꺼내야 합니다.- 이 패턴은 정수 리스트뿐 아니라 다양한 Java Stream 실습에서 자주 사용됩니다.
—

마무리 정리 표
| 항목 | 내용 |
|---|---|
| 사용 개념 | Java Stream, 객체 리스트 |
| 핵심 메서드 | stream(), mapToInt(), max(), min(), orElse() |
| 결과 타입 | OptionalInt |
| 최댓값 | 89 |
| 최솟값 | 12 |
| 배운 점 | 리스트를 Stream으로 바꿔 간단하게 숫자 계산 가능 |
| 초보자 팁 | OptionalInt는 비어 있을 가능성을 대비한 안전 장치 |
Java Stream은 처음엔 낯설지만, 한 번 익혀 두면 객체 리스트를 다루는 코드가 훨씬 간결해집니다. 이번 실습처럼 max()와 min()부터 차근차근 연습하면 금방 익숙해질 수 있습니다.

저는 대학에서 컴퓨터 관련 학과 학생들을 가르치고 있는 교수 김기태입니다. Spring Boot, React, Python 등을 활용한 풀스택 웹 개발과 최신 AI 서비스 설계를 주로 다루고 있으며, 학생들이 현업 실무에 바로 적용할 수 있는 기술 역량을 키울 수 있도록 강의와 실습을 설계하고 있습니다.


