스트림이라는 새로운 API를 제공
프로그래밍 언어에서 함수 function 라는 용어는 메서드method 특히 정적 메서드static method와 같은 의미로 사용된다. 자바의 힘수는 이에 더해 수학적인 함수처럼 사용되며 부작용을 일으키지 않는 함수를 의미한다.
프로그래밍 언어의 핵심은 값을 바꾸는 것이다. 이 값을 일급(first-class) 값 (또는 시민 citizen)이라고 부른다.
자바의 메서드,클래스는 자유롭게 전달 할 수 없어서 이급 시민이다.
예를들어 런타임에 메서드를 전달할 수 있다면, 즉 메서드를 일급 시민으로 만들면 프로그래밍에 유용하게 활용 할 수 있다. 자바 8 설계자들은 이급 시민을 일급 시민으로 바꿀 수 있는 기능을 추가했다.
준비된 함수를 메서드참조 :: 를 통해서 전달 할 수 있다.
File[] hiddenFiles = new File(".").listFiles(new FileFilter() {
public boolean accept(File file) {
return file.isHidden(); //숨겨진 파일 필터링
}
});
File[] hiddenFiles= new File(".").listFiles(File::isHidden);
자바 8에서는 (기명 named) 메서드를 일급값으로 취급할 뿐 아니라 람다(익명 힘수 anonymous functions)를 포함하여 함수도 값으로 취급 할 수 있다.
Apple 클래스와 getColor 메서드가 있고, Apples 리스트를 포함하는 변수 inventory가 있다고 가정하자. 이때 모든 녹색 사과를 선택해서 리스트를 반환하는 프로그램을 구현하려고 한다. 이처럼 특정 항목을 선택해서 반환하는 동작을 filter라고 한다.
자바 8 이전
public static List<Apple> filterGreenApples(List<Apple> inventory) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if ("green".equals(apple.getColor())) {
result.add(apple);
}
}
return result;
}
사과를 무게로 필터링하는 경우는 다음과 같을 것이다.
public static List<Apple> filterHeavyApples(List<Apple> inventory) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (apple.getWeight() > 150) {
result.add(apple);
}
}
return result;
}
소프트웨어공학적인 면에서 복붙의 단점 → 어떤 코드에 버그가 있다면 복붙한 모든 코드를 고쳐야 한다. 위의 두 코드는 한 줄의 코드만 다르다. 이러한 위험에서 안전하지 않기도 하다.
자바 8에서는 코드를 인수로 넘겨줄 수 있으므로 filter 메서드를 중복으로 구현할 필요가 없다. 자바 8에서는 다음과 같이 구현할 수 있다.
public static boolean isGreenApple(Apple apple) {
return "green".equals(apple.getColor());
}
public static boolean isHeavyApple(Apple apple) {
return apple.getWeight() > 150;
}
public static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> p) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (p.test(apple)) {
result.add(apple);
}
}
return result;
}
다음과 같이 호출할 수 있다.
filterApples(inventory, Apple::isGreenApple);
filterApples(inventory, Apple::isHeavyApple);
filterApples는 Apple::isGreenApple 메서드를 Predicate이라는 타입의 파라미터로 받는다. 인수로 값을 받아 true나 false를 반환하는 함수를 프레디케이트라고 한다.
리스트에서 고가의 트랜잭션Tran.saction(거래 )만 필터링한 다음에 통화로 결과를 그룹화해야 한다고 가정하자. 다음 코드처럼 많은 기본 코드를 구현해야 한다.
import static java.util.stream.Collectors.groupingBy;
Map<Currency, List<Transaction>> transactionsByCurrencies =
transactions.stream()
.filter((Transaction t) -> t.getPrice() > 1000) // 고가의트랜잭션필터링
.collect(groupingBy(Transaction::getCurrency)); // 통화로그룹화함
스트림 API는 기존 자바에서 발생하던 두가지 문제를 모두 해결했다.
자주 반복되는 패턴으로 주어진 조건에 따라 데이터를 ‘필터링'하거나 , 데이터를 ‘추출' 하거나, 데이터를 ‘그룹화'하는 기능등의 반복되는 패턴을 제공한다. 또한 이러한 동작들을 쉽게 병렬화 할 수 있다.
컬렉션은 어떻게 데이터를 저장하고 접근할지에 중점을 두는 반면 스트림은 데이터에 어떤 계산을 할것인지 묘사하는 것에 중점을 둔다.
자바 모듈 시스템은 모듈을 정의하는 문법을 제공한다. 이를 통해 패키지 모음을 포함하는 모듈을 정의할 수 있다.
모듈 덕분에 JAR 같은 컴포넌트에 구조를 적용할 수 있으며 문서화와 모듈 확인 작업이 용이해졌다.
또한 자바 8에서는 인터페이스를 쉽게 바꿀 수 있도록 디폴트 메서드를 지원한다.
구현 클래스에서 구현하지 않아도 되는 메서드를 인터페이스에 추가할 수 있는 기능을 제공하며, 메서드 본문은 클래스 구현이 아니라 인터페이스 일부로 포함된다.
예를 들어 자바 8에서는 List에 직접 sort 메서드를 호출할 수 있다. 이는 자바 8의 List 인터페이스에 다음과 같은 디폴트 메서드 정의가 추가되었기 때문이다.
default void sort(Comparator<? super E> C) {
Collections.sort(this, c);
}
함수형 언어에는 명시적으로 서술형의 데이터를 이용해 null을 회피하는 기법이 있다.
자바 8에서는 NullPointer 예외를 피할 수 있도록 도와주는 Optional 클래스를 제공한다.
Optional〈T〉는 값을 갖거나 갖지 않을 수 있는 컨데이너 객체다.
Optional는 값이 없는 상황을 어떻게 처리할지 명시적으로 구현하는 메서드를 포함하고 있다.