병렬성을 고려했기 때문에 이와 같은 설계를 포기하고 filter와 비슷한 동작을 수행하는 연산집합을 포함하는 새로운 스트림 API를 제공하게 된 것이다.
1.4 스트림
스트림 API를 이용하면 컬렉션 API와는 상당히 다른 방식으로 데이터를 처리할 수 있다.
컬렉션에선는 반복 과정을 직접 처리 : 외부 반복
스트림 API에서는 라이브러리 내부에서 모든 데이터가 처리 : 내부 반복
컬렉션으로는 멀티 코어를 활용할 수 없다.
1.4.1 멀티스레딩은 어렵다
멀티스레딩 환경에서 각각의 스레드는 동시에 공유된 데이터에 접근하고, 데이터를 갱신할 수 있다.
결과적으로 스레드를 잘 제어하지 못하면 원치 않는 방식으로 데이터가 바뀌기 때문에 멀티스레딩 모델은 순차적인 모델보다 다루기가 어렵다.
자바 8은 스트림 API로 컬렉션을 처리하면서 발생하는 모호함과 반복적인 코드 문제 그리고 멀티 코어 활용 어려움이라는 두 가지 문제를 모두 해결했다.
기존 컬렉션에서는 데이터를 처리할 때 반복되는 패턴이 너무 많았다. => 반복되는 패턴을 제공한다면 좋을 것이라는 아이디어가 변화의 동기
데이터를 연산하는 동작들을 쉽게 병렬화할 수 있다는 점도 변화의 동기가 되었다.
멀티 코어 환경에서 리스트를 필터링할 때 한 코어는 리스트의 앞 부분을 처리하고, 다른 코어는 리스트의 뒷부분을 처리하도록 요청할 수 있다. (포킹 단계)
컬렉션은 어떻게 데이터를 저장하고 접근할지에 중점을 두는 반면 스트림은 데이터에 어떤 계산을 할 것인지 묘사하는 것에 중점을 둔다
스트림은 스트림 내의 요소를 쉽게 병렬로 처리할 수 있는 환경을 제공한다는 것이 핵심이다.
컬레션을 필터링할 수 있는 가장 빠른 방법은 컬렉션을 스트림으로 바꾸고, 병렬로 처리한 다음에 리스트로 다시 복원하는 것이다.
스트림 API를 이용해 리스트에서 요소들을 순차적으로 또는 병렬로 필터링할 수 있다.
// 순차 처리 방식
List<Apple> heavyApples =
inventory.stream().filter((Apple a) -> a.getWeight() > 150)
.collect(toList());
// 병렬 처리 방식
List<Apple> heavyApples =
inventory.parallelStream().filter((Apple a) -> a.getWeight() > 150)
.collect(toList());
자바의 병렬성과 공유되지 않은 가변 상태
자바 8은 라이브러리에서 분할을 처리, 즉 큰 스트림을 병렬로 처리할 수 있도록 작은 스트림으로 분할한다.
filter와 같은 라이브러리 메서드로 전달된 메서드가 상호 작용을 하지 않는 메서드라면 가변 공유 객체를 통해 공짜로 병렬성을 누릴 수 있다.
메서드가 상호 작용하지 않는다 것의 의미
메서드가 상호 작용하지 않는다는 것은 메서드 내에서 호출 관계가 없고, 공유되는 상태를 변경하지 않으며, 외부에 부수 효과를 발생 시키지 않는다는 것이다.
즉, 메서드에 인자로 주어지는 입력에만 의존하고 메서드 외부의 상태는 건드리지 않는다는 것이다.
1.5 디폴트 메소드와 자바 모듈
자바 8이 등장하기 전까지는 인터페이스를 업데이트하려면 해당 인터페이스를 구현하는 모든 클래스도 업데이트 해야했다.
자바 8에서는 이러한 문제를 디폴트 메서드로 해결할 수 있다.
자바 8은 구현 클래스에서 구현하지 않아도 되는 메서드를 인터페이스에 추가할 수 있는 기능을 제공한다.
메서드 본문은 클래스 구현이 아니라 인터페이스의 일부로 포함된다. 이를 디폴트 메서드락고 부른다.
디폴트 메서드를 이용하면 기존의 코드를 건드리지 않고도 원래의 인터페이스 설계를 자유롭게 확장할 수 있다.
자바 8에서는 List에 직접 sort 메서드를 호출할 수 있는데 이는 자바 8의 List 인터페이스에 디폴트 메서드 정의가 추가되었기 때문이다.
default void sort(Comparator<? super T> c){
Collections.sort(this, c);
}
하나의 클래스에서 여러 인터페이스를 구현할 수 있는데, 여러 인터페이스에 동일한 시스니처의 디폴트 메서드가 존재하는 경우엔, 구현 클래스에서 디폴트 메서드를 재정의해야 한다.
1.6 함수형 프로그래밍에서 가져온 다른 유용한 아이디어
자바에 포함된 함수형 프로그래밍의 핵심적인 두 가지 아이디어
메서드와 람다를 일급값으로 사용
가변 공유 상태가 없는 병렬 실행을 이용해서 효율적이고 안전하게 함수나 메서드를 호출
함수형 언어는 명시적으로 서술형의 데이터 형식을 이용해 null을 회피하는 기법으로 프로그램을 돕는다.
이러한 아이디어를 기반으로 자바 8에서는 NullPointer Exception을 피할 수 있도록 도와주는 Optional< T > 클래스를 제공한다.
Optional< T > 타입의 객체는 값을 갖거나 갖지 않을 수 있는 컨테이너 객체다.
Optional< T > 클래스는 값이 없는 상황을 어떻게 처리할 지 명시적으로 구현하는 메서드를 포함하고 있다 => NullPointer Exception을 피할 수 있다.