멀티코어 CPU 대중화 등 하드웨어의 발전은 자바의 변화를 부추겼다
프로그래밍 언어의 핵심은 값(=시민)을 바꾸는것
자바언어의 다양한 구조체(메서드,클래스 등)은 프로그램을 실행하는동안 자유롭게 전달할 수는 없다(= 2급시민)
자바8은 2급시민을 1급 시민으로 바꾸는 기능을 추가함
메서드에 코드를 전달하는 기법은 동적 파라미터화를 구현할 수 있다.
예를 들어, 비슷하지만 다른 동작을 하는 두 메소드를 각각 작성하는 것보다는
파라미터에 따라 다른 동작을 하도록 구현하는 것이 코드의 길이와 에러를 줄이는데에 더 바람직하다
스트림 API는 연산의 동작을 파라미터화 할 수 있는 코드를 전달한다는 사상에 기초한다는 점에서 중요함.
// 디렉토리 내 모든 숨겨진 파일을 필터링하는 메소드
// 이미 isHidden 메소드를 가지고 있음에도 FileFilter라는 객체를 이용해야 필터링이 가능
// 가독성도 좋지않다.
File[] hiddenFiles = new File(".").listFiles(new FileFilter(){
public boolean accept(File file){
return file.isHidden();
}
});
// java 8에서 동일한 기능 수행
File[] hiddenFiles = new File(".").listFiles(File::isHidden);
// before
Runnable runnable = new Runnable(){
@Override
public void run(){
System.out.println(*"Hello world !"*);
}
};
// after
Runnable runnable = () -> System.out.println(*"Hello world two!"*);
스트림 API는 파이프라인을 만드는데 필요한 많은 메소드를 제공
이는 작업을 고수준으로 추상화해 일련의 스트림으로 만들어 처리가능하고 스레드라는 복잡한 작업을 사용하지 않으면서도 파이프라인을 이용해 입력부분을 여러 CPU 코어에 쉽게 할당 가능해 공짜로 병렬성을 얻을 수 있다
// 모호함과 반복적인 코드문제 또한, 멀티코어 활용의 어려움을 해결함
List<String> list = Arrays.asList("franz", "ferdinand", "fiel", "vom", "pferd");
list.stream()
.filter(name -> name.startsWith("f"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
// 기존의 컬렉션은 어떻게 데이터를 저장하고 접근할지를 중점적으로 보고
// 스트림은 데이터에 어떤 계산을 할 것인지 묘사하는 것을 중점적으로 본다
import static java.util.stream.Collectors.toList;
// 순차 처리
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());
x라는 변수를 A와 B 메소드가 사용한다고 생각해보자. 병렬로 실행되지 않을 때는 어렵지 않게 원하는 x 값을 구할 수 있지만, 병렬로 실행될 경우 A와 B의 실행 순서를 보장하기 어렵고, 그에 따라 원하는 결과를 얻을 수 없을 확률이 더 높을 것이다.
이 때, x를 공유된 가변 데이터라고 부르며, 여기에 접근을 하지 않도록 코드를 작성해야 한다. 기존의 자바에서는synchronized
키워드를 통해 보장이 가능하지만 성능상 그리 좋지 않았다.
JAVA 8에서는 스트림을 이용하여 쉽게 사용할 수 있다.
인터페이스에 메소드를 추가할때마다 인터페이스를 구현한 모든 클래스에도 메소드를 추가해야한다는건 매우 고통스럽다.
Java 8에서는 구현하지 않아도 되는 메소드를 인터페이스에 추가할 수 있는 기능을 제공하는데 이것이 바로 디폴트 메소드
null 참조를 만든 것은 10억 달러짜리 실수였다 - Tony Hoare
모듈 시스템 등장
Jigsaw(직소) 프로젝트 기반하에 개발된 Java9 Module 시스템은
안정적인 구성과 강력하고 유연한 캡슐화를 제공
1. 모듈 시스템
2. 컬렉션
3. 스트림
4. optional
5. 인터페이스
code - type을 포함하고 있는 packages (class, interface 등)
data - resources 등 정적 정보
Class는 field와 method를 포함
Package는 Class와 Enum, Interface, 설정파일등을 포함
Module은 Package와 다른 데이터 자원들을 포함
list, set, map을 쉽게 구성할 수 있는 몇 가지 기능 추가
List<String> list = List.of("one", "two", "three");
Set<String> set = Set.of("one", "two", "three");
Map<String, String> map = Map.of("foo", "one", "bar", "two");
takeWhile, dropWhile, iterate 메서드의 형태로 기능 추가
List<Integer> list = List.of(1, 2, 3, 4, 5);
List<Integer> result = list.stream()
.takeWhile(x -> x < 4)
.collect(Collectors.toList());
// result = [1, 2, 3]
List<Integer> list = List.of(1, 2, 3, 4, 5);
List<Integer> result = list.stream()
.dropWhile(x -> x < 4)
.collect(Collectors.toList());
// result = [4, 5]
Stream<Integer> stream = Stream.iterate(0, x -> x + 1);
List<Integer> result = stream.limit(5)
.collect(Collectors.toList());
// result = [0, 1, 2, 3, 4]
ifPresentOrElse 기능 추가
user.ifPresentOrElse(this::displayAccount, this::displayLogin);
// calculate 메서드는 getSpeed에만 사용되는 메서드로 인터페이스
// 외부에 표시되지 않으며 Vehicle 인터페이스를 구현하는 모든 클래스에서 구현할 필요가 없다
public interface Vehicle {
void drive();
default double getSpeed(double distance, double time) {
double speed = calculateSpeed(distance, time);
return speed;
}
private double calculateSpeed(double distance, double time) {
return distance / time;
}
}
var 키워드
병렬처리 가비지 컬렉션 도입으로 성능 향상
Java 10부터는 소스파일을 먼저 컴파일하지 않고도 실행할 수 있다.
- local-variable type inference at compile time
- 스크립팅을 향한 한 걸음
`var name = "John";`
(var firstName, var lastName) -> firstName + lastName
https://www.oracle.com/java/technologies/javase/8-whats-new.html
https://jyukki.tistory.com/19
https://siyoon210.tistory.com/125
https://zorba91.tistory.com/339
https://girawhale.tistory.com/127
https://www.baeldung.com/java-when-to-use-parallel-stream