본문 바로가기

카테고리 없음

[JAVA] JDK 버전별 정리

JDK 버전별 변화와 특징을 정리하였다.

 

1996년 자바 개발 키트(JDK 1.0) 

1997년 자바 1.1 


  • 자바 1.0 스레드 락, 심지어 메모리 지원했지만 저수준 기능을 온전히 활용하기 어려움이 있다.

 

JDK 5


특징)

자바 5는 이전 버전과 비교해서 언어적으로 큰 변화가 있었다, 스레드 풀, 병령 실행 컬렉션의 강력한 도구 도입 

 

릴리즈) 

1. 제너릭 

 자바 5의 가장 중요한 신규 기능이다. 기존에 컬렉션 프레임워크를 이용해 발생할 수 있는 ClassCastExption 을 

컴파일 시간에 검증 할 수 있다. 이러한 컴파일 검증 기능 뿐만 아니라 코드에 대한 데이터를 명확히 해서 가독성을 높일 수 있다.

2. for 루프 개선 

 for each 구문을 사용할 수 있다. 

3. 컨커런스 API

API 를 사용해서 병렬 프로그래밍 혹은 멀티 스레드를 손쉽게 구현할 수 있었다. 

4. 어노테이션 

5. Enum

자바 개발자들은 데이터 구조를 더 손쉽게 정의하고 사용할 수 있는 열거형(Enum) 기능을 원했고 자바 5에 추가되었다. 이를 이용해 클래스, 인터페이스 열거형으로, 소스 코드를 작성 할 수 있게 되었다. 

6. 오토박싱/ 언박싱  

 오토박싱/ 언박시 기능을 통해 개발자가 기본형 데이터를 래퍼 클래스로 직접 변환하지 않아도 언어 차원에서 자동 변환이 가능하도록 보강 되었다. 

 

JDK 6


특징)

자바 5의 안정화 버전. 새로운 기능은 거의 없고 가비지 컬렉션이나 동기화, 자바 가상 머신의 성능향상에 중점

 

릴리즈) 

1. G1 가비지 콜렉션 

 G1 가비지 컬렉터는 정확히는 버전 6의 중간 버전부터 추가된 기능으로 기존에는 힙 메모리 영역을 영과 올드 영역으로 분할해서 관리했지만 버전 6부터는 해당 영역 구분을 없애고 1MB 크기의 영역(Region)으로 구분해서 메모리를 관리한다. Full GC 발생을 최소화 하기 위함이다. 자바 7부터는 기본 가비지 컬렉터로 사용한다. 

2. 데스크톱 API 

3. 자바 컴파일러 API 

 자바 코드에서 직접 컴파일러를 호출 할 수 있는 API 제공. 이를 통해 자바 애플리케이션에서 자바 소스 코드를 컴파일하고 실행  

 

 

JDK 7


특징) 

  • 자바 7 병렬 실행에 도움을 줄 수 있는 포크/조인 프레임 워크 제공했지만 여전히 개발자 활용 어려움

릴리즈) 

[참고하기 - NAVER D2 - JDK7]

 

1. File NIO 2.0 

 파일 처리를 위한 새로운 기능을 제공. 기존에 사용하던 java.io.File 클래스와 개념이 완전히 다르다. 

2. 포크/조인 프레임 워크 

 자바 5에서 처음 등장한 컨커런스 API 에 포크/조인 기능이 추가 되었다. 이 기능을 이용하면 기존에 멀티 스레드를 생성하는 것에 더해 라이프 사이클을 관리하고 모니터링 할 수 있다. 

3. 다이아몬드 연산자

 제너릭의 선언 방법이 개선되었다. 객체 생성시 제네릭 타입을 다시 기입할 필요 없이 다이아몬드 연산자만 기술하면 된다. 

4. try-with-resource 

5. 예외 처리 - 하나의 catch 절에 여러개의 Exception 을 처리 할 수 있도록 개선했다. 

 

 

JDK 8 (Long Term Support, LTS)


특징)

 

자바 역사를 통틀어 가장 큰 변화가 자바 8에서 일어났다.

자바 9에서도 중요한 변화가 있었지만 8만큼 획기적이거나 생산성이 바뀌는 것은 아니었다. 

 

릴리즈)

[참고하기 - 자바 8부터 16까지의 신규 기능들 정리]

 

 1. 람다 표현식 - annonymous inner class 표현 간략화

 별도의 익명 클래스를 만들어서 선언하던 방식을 람다를 통해 대폭 간소화 할 수 있으며, 함수형 프로그래밍, 스트림 API 그리고 컬렉션 프레임워크의 개선등에 영향을 주었다. 

 

 2. 함수형 인터페이스 

 함수형 인터페이스는 람다 표현식을 사용할 때 만들어야 하는 하나의 메서드를 가진 인터페이스 생성을 줄여준다. 또한 람다 표현식을 위한 인터페이스 사용시 표준 가이드 및 의사소통 용어로도 사용한다. 

 

 3. 메서드 참조 - 인자로 method reference를 전달 (함수형 표현)

 기존에는 값과 객체 참조만을 메서드의 인수로 전달 할 수 있었지만 자바 8 부터는 특정 메서드를 메서드의 인수로 전달 할 수 있게 되었다.

 

4. 스트림 API - Collections 에서 Streams API 를 사용하여 , 이전의 반복문이 아닌 함수형 구현

 람다 표현식, 함수형 인터페이스 그리고 메서드 참조를 이용한 최종 산출물.  기존 컬렉션 프레임워크를 이용할 때보다 간결하게 코드를 작성 할 수 있다.  병렬처리, 스트림 파이프라인등을 통해 하나의 문장으로 다양한 처리 기능을 구현 가능하다. 

 

5. 날짜와 시간 API 

 기존 Date 와 Calendar 클래스의 기능 부족과 비 표준적인 명명 규칙, 그리고 일관되지 못한 속성 값의 문제를 해결하기 위해 새롭게 추가되어 개발자들의 혼란 최소화 

 

6. 인터페이스 개선 - interface 내부에서 default 메서드를 선언할 수 있다.

 Default 키워드를 이용해 인터페이스에 메서드를 추가하고 직접 내용을 정의할 수 있어서 인터페이스의 메서드 추가로 인한 문제점을 해소 할 수 있다. 

 

7. Optional - Optional Class 를 이용하여 NullPointerException 이 발생하는 것을 방지해 준다.

 null 값을 확인하고 관리할 수 있는 기능

 

8. CompletableFuture 

 자바 8 에서 멀티 스레드 프로그래밍 시에 중요한 기능 중 하나가 Completable Future 이다. CompletableFuture는 기존 Future 인터페이스에서 제공하는 기능을 개선하였다.

 

 

특징 - 2 ) 

 

자바 8은 간결한 코드, 멀티 코어 프로세서의 쉬운 활용이라는 두가지 요구 사항을 기반으로 한다. 

https://johngrib.github.io/wiki/java-enhancements/

 

 

- 메서드에 코드를 전달하는 기법 

- 인터페이스의 디폴트 메서드 

 

  • 자바 8 - 병렬 실행을 새롭고 단순한 방식으로 접근 할 수 있는 방법 제공
Collections.sort(inventory, new Comparator<Aapple>() {
	public int compare(Apple a1, Apple a2) {
    	return a1.getWeight.compareTo(a2.getWeight()); 
    }
});

 자바 8을 이용하면 자연어에 더 가깝게 간단한 방식으로 코드를 구현할 수 있다. 

inventory.sort(comparing(Apple::getWeight));

 

멀티 코어 CPU 대중화와 같은 하드웨어적인 변화도 자바 8에 영향을 미쳤다. 

 

자바 8의 메서드 참조   (':: 이 메서드를 값으로 사용하라'는 의미)

File[] hiddenFiles = new File(".").listFiles(new FileFilter() {
	public boolean accept(File file) {
    	return file.isHidden();
    }
});
File[] hiddenFiles = new File(".").listFiles(File::isHidden);

 

기존에 객체 참조(new 로 객체 참조를 생성함)를 이용해서 객체를 이리저리 주고 받았던 것처럼 자바 8에서는 

File::isHidden을 이용해서 메서드 참조를 만들어 전달할 수 있게 되었다.

 

람다 : 익명 함수

자바 8에서는 메서드를 일급값으로 취급 할 뿐 아니라 람다를 포함하여 함수도 값으로 취습한다. 

예를 들어  (int x) -> x+1, 즉 'x라는 인수로 호출하면 x + 1 을 반환' 하는 동작을 수행하도록 코드를 구현할 수 있다. 

 

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);
        }
    }

}

 

자바 8에서는 코드를 인수로 넘겨줄 수 있으므로 filter 메서드를 중복으로 구현할 필요가 없다. 

앞의 코드를 다음처럼 자바 8에 맞게 구현할 수 있다. 

 

public static boolean isGreenApple(Apple apple). {
	return GREEN.equals(apple.getColor();
}
public static boolean isHeavyApple(Apple apple) {
	return apple.getWeigth() > 150;
}
public intnerface predicate<T> {
	boolean test(T t); 
}
static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> p) {
	List<Apple apple : inventory) {
    	if(p.test(apple)) {
        	result.add(apple);
        }
    }
    return result;
}

다음처럼 메서드를 호출할 수 있다.

filterApples(inventory, Apple::isGreenApple);

또는 다음과 같이 호출해도 된다. 

filterApples(inventory, Apple::isHeavyApple);

 

메서드를 값으로 전달하는것은 유용한 기능이지만 isHeavyApple, isGreenApple 처럼 한 두번만 사용할 메서드를 매번 정의하는 것은 귀찮은 일이다. 자바 8에서는 이 문제도 익명 함수 또는 람다라는 새로운 개념을 이용해서 코드를 구현 할 수 있다. 

filterApples(inventory, (Apple a) -> GREEN.equals(a.getColor()) );

또는 다음과 같이 구현한다. 

filterApples(inventory, (Apple a) -> a.getWeight() > 150);

심지어 다음과 같이 구현 할 수도 있다. 

filterApples(inventory,(Apple a) -> a.getWeight() < 80 || RED.equals(g.getCollor()) );

즉, 한 번만 사용할 메서드는 따로 정의를 구현할 필요가 없다. 위 코드는 우리가 넘겨 주려는 코드를 애써 찾을 필요가 없을 정도로 더 짧고 간결하다. 

 

 하지만 람다가 몇줄 이상으로 길어진다면( 즉, 조금 복잡한 동작을 수행하는 상황) 익명 람다 보다는 코드가 수행하는 일을 잘 설명하는 이름을 가진 메서드를 정의하고 메서드 참조를 활용 하는 것이 바람직하다. 코드의 명확성이 우선시 되어야 한다.

 

또한 다음처럼 라이브러리 메서드 filter 를 이용하면 filterApple 메서드를 구현할 필요가 없다. 

filter(inventory, (Apple a) -> a.getWeight() > 150);

 

- 스트림 API 

 

리스트에서 고가의 트랜잭션(거래)만 필터링 한 다음에 통화로 결과를 그룹화해야한다고 가정하자. 

다음 코드 처럼 많은 기본 코드를 구현해야 한다. 

Map<Currency, List<Transaction>> transactionsByCurrencies = new HashMap<>(); 
for (Trransaction transaction : transactions) {
	if(transaction.getPrice() > 1000) {
    	Currency currency = transaction.getCurrency(); 
        List<Transaction> transactionForCurrency = 
             transactionsByCurrencies.get(crrency); 
        if(transactionForCurrency == null) {
        	transactionForCurrency = new ArrayList<>(); 
            transactionsByCurrencies.put(currency, transactionForCurrency); 
        }
        transactionForCurrency.add(transaction);
    }

}
import static java.util.stream.Collectors.groupingBy; 
Map<Currency, List<Transaction>> transactionsByCurrencies = transactions.stream()
	.filter((Transaction t) -> t.getPrice() > 1000)
    .collect(groupingBy(transaction::getCurrenct));

 

자바 9 


특징)

 자바 9에서도 중요한 변화가 있었지만 8만큼 획기적이거나 생산성이 바뀌는 것은 아니었다.  자바 10에서는 형 추론과 관련한 약간의 변화만 일어났다. 

릴리즈) 

 리액티브 프로그래밍

  리액티브 프로그래밍이라는 병렬 실행 기법 제공. 이 기법을 사용할 수 있는 상황은 한정되어있지만 요즘 수요가 많은 고성능 병렬 시스템에서 특히 인기를 얻고있는 RxJava(리액티브 스트림 툴킷이라고도 불림) 를 표준적인 방식으로 지원 

 

 

자바 11 (Long Term Support, LTS) 

 

1. HTTP 클라이언트 

자바 9에 인큐베이팅 형태로 넣었던 HTTP 클라이언트 API 를 정식적으로 포함했다. 이 API 는 기존에 제공되는 URLConnection 기반의 HTTP 개발보다 개선된 기능과 명명규칙을 제공한다. 특히 HTTP 2.0을 지원하여 웹 소캣 기능도 포함되어있다. 

 

2. 컬렉션 객체를 배열로 변경하는 기능 

컬렉션 인터페이스에 ToArray 메서드가 추가되었다. 이 메서드를 통해서 컬렉션 객체를 배열로 변환하면 별도의 반복문을 작성하지 않고 메서드 호출만으로 처리 할 수 있다. 

 

3. var 키워드 지원 확대 

 자바 10에서 var 키워드로 변수를 선언하면 타입 추론으로 객체를 생성할 수 있는 기능이 추가되었다. 자바 11에서는 여기에 더해 람다 표현식에서도 var 를 사용해서 변수를 선언할 수 있게 했다. 

기존에 (string x) -> System.out.println(x) 하던것을 

(var x) -> System.out.pringln(x) 처럼 사용할 수 있다. 

 

4.String 클래스 기능 추가 

 문자열을 표현하는 String 클래스에 편리하게 사용할수 있는 메서드 추가 

블랭크를 판단하는 isBlank

여러줄로 되어있는 문자열을 스트림 api 객체로 생성할 수 있는 lines

공백을 지우기 위함 strip, stripLeading, stripTrailing 등을 추가

 

 

자바 17 (Long Term Support, LTS) 

JDK 발표 및 새로운 변화

 

LTS 주기 변경

JDK 17을 기준으로, LTS 버전에 대한 주기를 기존의 3년에서 2년으로 변경하도록 제안하였다.

 

https://johngrib.github.io/wiki/java-enhancements/

반응형