자료 보관함/Java | SpringBoot

[Java] Java 배열에서 stream() 이해하기: filter, map, forEach 정리

dev.jelee 2025. 5. 18. 23:55

# 예시

Arrays.stream(names)
	.filter(name -> name.startsWith("A"))
	.map(String::toUpperCase)
	.forEach(System.out::println);

 

# 설명

  • .stream(names)
    • : names 배열 또는 컬렉션의 원소를 하나씩 꺼내 스트림으로 생성한다.
    • 스트림으로 생성한다는 의미: 데이터를 저장하지 않고, 데이터에 순차적으로 연산을 적용하는 처리 방식
    • 스트림 방식은 필터 -> 변환 -> 출력 단계로 흐르는 것처럼 보인다.
    • 즉, 처리 흐름을 선언적으로 표현한다.
    • 하나씩 원소를 흘려보낼 수 있는 처리 파이프라인을 만들어준다는 뜻.
  • .filter(name -> name.startsWith("A"))
    • : name 매개변수에 names에서 하나씩 꺼낸 원소를 담아 A로 시작하는 글자가 있는지 비교하여 다음 단계로 넘긴다. (조건을 비교하여 true인 데이터만 다음 단계로 넘기기.)
  • .map(String::toUpperCase)
    • : filter를 통과한 데이터를 대문자로 변환한 후 다음 단계로 넘긴다.
  • .forEach(System.out::println)
    • : 최종적으로 변환된 데이터를 하나씩 꺼내어 출력하기.

 

# 메서드 요약 설명

메서드 역할 요약
.stream() 데이터 흐름 생성 (배열 -> 스트림)
.filter() 조건을 걸러내기 (true만 다음 단계로 전달)
.map() 데이터를 다른 형태로 변환
.forEach() 변환된 데이터를 최종적으로 소비/출력

 

 

# 메모

Q) .map(String::toUpperCase)와 .forEach(System.out::println) 에서 :: 이 기호는 무엇인가?

  • Java에서 :: 는 "메서드 참조(Method Reference)" 라고 부른다.
  • 람다(lamda)를 간단하고 간결하게 표현하기 위한 문법이다.
  • 즉, 람다 표현식의 간단한 축약형이다.

예시를 보면 쉽게 이해가 된다.

// 1. 람다 표현식
.map(name -> name.toUpperCase())
.forEach(name -> System.out.println(name));

// 2. 메서드 참조
.map(String::toUpperCase)
.forEach(System.out::println);

 

Q) 왜 :: 를 쓰는가?

  • 코드 간결성, 가독성 향상, 재사용성, 함수형 스타일

 

Q) 어떨 때 "메서드 참조"를 사용하는가?

"딱 한 줄" 메서드 호출일 때만 사용한다. 복잡하거나 의미 전달이 중요한 경우에는 람다식이 더 친절하고 안전하다.

// 메서드 참조가 람다보다 나은 경우

// 1. 람다 내부가 메서드 한 줄 호출일 때
list.forEach(item -> System.out.println(item));
list.forEach(System.out::println);

// 2. 의도가 분명할 때
.stream().map(s -> s.toLowerCase())
.stream().map(String::toLowerCase)

// 3. 중복된 표현을 줄이고 싶을 때
.sort((a, b) -> a.compareTo(b));
.sort(String::compareTo);

 

// 람다식이 더 나은 경우 (메서드 참조는 피해야 하는 경우)

// 1. 로직이 복잡하거나 여러 줄일 때
// 조건문, 반복문 등 롲기이 포함된 경우는 람다식 필수
list.forEach(item -> {
	if (item.startWith("A")) {
    	System.out.println(item.toUpperCase());
    }
});


// 2. 가독성이 떨어지는 경우
// 메서드 이름만 봐서는 뭐하는지 불명확한 경우.
list.stream()
	.map(MyClass:process) // process가 뭘 하는지 모르면 혼란

// 3. 파라미터 조작이 필요한 경우
// 메서드에 직접 값을 넣는 조작은 람다식만 가능하다.
list.stream()
	.map(s -> s.substring(0, 3))