키오스크의 기능을 더 확장하고, 효율적으로 개선하기 위해 stream()을 사용했는데, 이 과정에서 forEach, filter, AtomicInteger를 배웠다.
이들은 함수형 스타일로 데이터를 처리하고, 값들을 안전하게 다룰 수 있는 방법을 제공해준다!
Stream은 java.util.stream 패키지의 일부로,
collection(ArrayList, HashSet 등)을 함수형 스타일로 처리할 수 있게 해준다.
데이터의 원본을 변경하지 않고, 데이터 처리 과정을 단계별로 구성하기 때문에 읽기 쉽게 작성할 수 있다!
필터링 (Filtering)
: 조건에 따라 데이터를 거른다
매핑 (Mapping)
: 데이터 변환
정렬 (Sorting)
: 데이터 정렬
집계 (Reduction)
: 데이터를 하나의 값으로 합침 (합계, 평균 등)
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class UseStream {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Edward");
// 'D'로 시작하는 이름을 필터링하고, 대문자로 변환하기
List<String> filteredNames = names.stream()
.filter(name -> name.startsWith("D"))
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(filteredNames); // 출력: [DAVID]
}
}
: 일반적인 int 변수와 다르게, AtomicInteger는 내부적으로 동기화 없이 원자적 연산(Atomic Operation)을 제공
: 한마디로 스트림이 함수형 스타일로 동작하기 때문이다.
스트림의 연산은 보통 람다 표현식으로 정의되고, 내부적으로 병렬 처리도 가능하다.
만약 int i 같은 변수를 사용하면 아래처럼 문제가 생기게된다,,
int i = 1;
List<String> list = Arrays.asList("A", "B", "C");
list.stream().forEach(item -> System.out.println(i++ + " 출력"));
위 코드를 컴파일하면 오류가 발생한다ㅠㅠ.
왜냐면, 스트림 내부의 람다 표현식에서 사용되는 i 변수는 지역 변수인데 그 값을 변경하려고 시도하기 때문!!!
💡 Java에서 람다 표현식 안에서는 "Effective final" 즉, 사실상 변경되지 않는 값들만 사용이 가능
AtomicInteger는 참조 타입이고, 내부에서 값을 안전하게 변경할 수 있는 메서드들을 제공한다.
→ 람다 표현식 안에서도 자유롭게 값을 변경 가능!!
AtomicInteger i = new AtomicInteger(1);
List<String> list = Arrays.asList("A", "B", "C");
list.stream().forEach(item -> System.out.println(i.getAndIncrement() + " 출력"));
i.getAndIncrement()는 AtomicInteger 클래스의 메서드 호출일 뿐, 참조 변수 i 자체는 변경되지 않음
→ 스트림 안에서도 안전하게 사용이 가능!!
✨ 참조 변수를 사용해서 내부 값을 바꾸는 건 허용, 기본 타입의 값을 직접 바꾸는 건 허용되지 않음!