반응형
Modern Java In Action 정리
Modern Java In Action을 읽고 내용을 정리해본다.
4장 스트림 소개
스트림(Stream)
데이터 처리 연산을 지원하도록 소스에서 추출된 연속된 요소
- 자바8에 추가된 기능으로 스트림을 이용하면 선언형으로 코드를 구현하여 컬렉션 데이터를 처리할 수 있다.
선언형으로 구현한다는 것은 for 루프나 if 조건문 등의 제어 블록을 사용하지 않고 동작을 지정하는 것이다.
→ 실제 구현은 신경쓰지 않고 사용하는 SQL를 생각하자. - 스트림에서 제공하는 filter, sorted, map, collect 같은 메서드들은 특정 스레딩 모델에 제한되지 않고 스레드와 락을 걱정할 필요없이 편리하게 데이터 병렬처리를 가능하게 해준다.
스트림 기본 구현
기본구현에 사용할 Dish 클래스
class Dish{ private final String name; private final boolean vegetarian; private final int calories; private final Type type; public Dish(String name, boolean vegetarian, int calories, Type type) { this.name = name; this.vegetarian = vegetarian; this.calories = calories; this.type = type; } public String getName() { return name; } public boolean isVegetarian() { return vegetarian; } public int getCalories() { return calories; } public Type getType() { return type; } enum Type { MEAT, FISH, OTHER } }
스트림 구현에 사용할 Dish 컬렉션
List<Dish> menu = Arrays.asList( new Dish("pork", false, 800, Dish.Type.MEAT), new Dish("beef", false, 700, Dish.Type.MEAT), new Dish("chicken", false, 400, Dish.Type.MEAT), new Dish("french fries", true, 530, Dish.Type.OTHER), new Dish("salmon", false, 450, Dish.Type.FISH) );
스트림 기본구현
@Test public void 스트림_기본구현(){ List<String> threeHighCaloricDishNames = menu.stream() // 컬렉션에서 스트림(Stream<Dish>)을 가져온다. .filter(dish -> dish.getCalories() > 300) // 해당 조건의 요소만 추출한다. .map(Dish::getName) // 이름(String) 속성을 스트림(Stream<String)으로 가져온다. .limit(3) // 3개를 제외하고 truncate한다. .collect(Collectors.toList()); // 스트림을 컬렉션(리스트)로 변환한다. System.out.println(threeHighCaloricDishNames); // [pork, beef, chicken] }
filter, map 메서드는 인자로 Functional Interface 인스턴스를 받기 때문에 람다표현식이나, 메서드참조로 간결하게 코딩이 가능하다. 또한 메서드들은 실행 결과로 스트림을 리턴하기 때문에 파이프라인 형태가 된다.
→ 빌더 패턴과 유사하다.서로 연결이 가능한 filter, map, limit는 중간연산이며, collect는 스트림을 닫는 최종연산이다.
스트림과 컬렉션
- 컬렉션은 DVD에 저장된 영화에 비유할 수 있다. 모든 데이터(영화 내용 전부)가 메모리(DVD)에 저장되어 있다.
컬렉션에는 계산된 결과물이 저장되어 있으며, 주 관심사는 특정요소에 접근하여 값을 계산하거나 치환한다. - 스트림은 인터넷으로 스트리밍하는 영화에 비유할 수 있다.
영화 전체를 모두 받는 것이 아니라 미리 몇 프레임만 내려받아 재생이 가능할 수 있다. 스트림은 이론적으로 요청할 때만 요소를 계산하는 고정된 자료구조다. - 스트림은 한번만 탐색이 가능하다.
이미 소비된 스트림을 사용하려 하면 Exception이 발생하므로 다시 생성하여 사용해야 한다. - 컬렉션은 데이터를 순회하기 위해서는 루프문을 이용해 명시적으로 반복해야 한다. → 외부반복
- 스트림은 반복을 알아서 처리(중간값 저장, 최적화, 병렬성 구현 등) 한다. → 내부반복
@Test public void 스트림_내부반복(){ // forEach 메서드에서 반복되며 명시적으로 루프문이 필요없다. menu.stream() .forEach(dish -> System.out.println(dish.getName())); }
스트림은 게으른(lazy) 연산을 지원
스트림 처리시 한 요소는 연결된 모든 파이프라인을 타고나서 다음 요소가 처리된다.
@Test public void 스트림_게으른_연산(){ List<String> threeHighCaloricDishNames = menu.stream() .filter((dish) -> { System.out.println("filtering :: " + dish.getName()); return dish.getCalories() > 300; }) .map((dish) -> { System.out.println("mapping :: " + dish.getName()); return dish.getName(); }) .limit(3) .collect(Collectors.toList()); System.out.println(threeHighCaloricDishNames); // [pork, beef, chicken] }
콘솔출력으로 스트림 처리 순서를 보면 한 요소씩 filter → map → limit → collect 파이프라인을 타는것을 볼 수 있다. 중간 연산들(filter → map → limit)을 합친 다음에 최종 연산(collect)에서 한 번에 처리한다.
filtering :: pork mapping :: pork filtering :: beef mapping :: beef filtering :: chicken mapping :: chicken [pork, beef, chicken]
반응형
'책정리 > Modern Java In Action' 카테고리의 다른 글
[책 정리]Modern Java In Action 2장 (0) | 2020.05.18 |
---|---|
[책 정리]Modern Java In Action 1장 (0) | 2020.05.18 |
[책 정리]Modern Java In Action 6장 (0) | 2020.05.18 |
[책 정리]Modern Java In Action 시작 (0) | 2020.05.18 |
[책 정리]Modern Java In Action 5장 (0) | 2020.05.18 |