[Java] - Java 8, 11 버전 특징

chancehee·2022년 11월 28일
0

자바

목록 보기
1/12
post-thumbnail

0. 글을 작성하는 이유

Java언어를 메인으로 사용하고 있지만, 단순히 Java 버전을 선택할 때 다른 사용자들이 많이 쓰는 점과 대략적인 이유로 Java 버전 8을 사용했습니다.
내가 사용하는 버전이 어떤 기능을 제공하며, 다른 사용자들이 많이 쓰는 이유는 무엇인지 알아보기 위해서 해당 글을 작성합니다.

1. 개요

1) 2022년 가장 많이 사용하고 있는 버전

2022년 뉴렐릭에서 조사한 통계에 따르면, Java 11버전의 사용이 가장 많다는 것을 알 수 있습니다.
2021년도에는 Java 8버전이 가장 우세했지만, 2022년도에는 Java 11버전으로 넘어온 유저들이 많습니다.
출처: https://newrelic.com/kr/resources/report/2022-state-of-java-ecosystem

2) LTS 버전이란

(Long Term Support)의 약자로, 오랜기간 동안 버그 픽스 등 패치를 해주는 버전을 의미합니다.
non-LTS 버전은 6개월 동안만 지원하기 때문에, 실제 서비스를 개발할때는 LTS버전 사용이 좋습니다.

2. Java 8 특징

Lambda expression(람다 표현식)

메서드로 전달할 수 있는 Anonymous function(익명 함수)를 단순한 문법으로 표기한 것을 의미합니다.

// 익명 클래스로 Runnable을 구현
Thread thread = new Thread(new Runnable() {
	@Override
    public void run() {
    	System.out.println("Start new thread!");
    }
});
thread.start();

// 람다 표현식으로 단순하게 표현
Thread thread = new Thread( () -> System.out.println("Start new thread!") );
thread.start();

이를 통해서 개발자가 더 쉽게 객체 지향 프로그래밍, 함수형 프로그래밍을 할 수 있게 합니다.
또한 언어의 표현이 더 풍부해지게 되었으므로, 간결한 코드의 작성이 가능하고 이는 가독성 증가, 단위 테스트 용이하다는 장점을 불러옵니다.

Functional interface(함수형 인터페이스)

Java의 메서드는 일급객체가 아니기 때문에 Java는 함수형 프로그래밍 언어가 아닙니다.
Java 8에서는 함수를 일급객체처럼 다룰 수 있게 함수형 인터페이스를 제공합니다.
함수형 인터페이스란, 1개의 추상 메소드를 갖는 인터페이스를 말합니다.(static 함수는 여러 개 가질 수 있습니다.)

// @FunctionalInteface는 생략가능합니다.
// 그렇지만, 인터페이스 검증과 유지보수를 위해 붙여주는 것을 권장합니다.
@FunctionalInterface
public interface Car {
	String drive(int driveLevel);
}

// 인터페이스 사용 !! 
// 1. 전통적인 방법 
Car car = new Car() {
	@Override 
    public String drive(int driveLevel) {
    	return driveLevel == 0 ? "" : "자동차가 " + driveLevel + " 의 속도로 이동";
    }
};
System.out.println(car.drive(10));

// 2. 람다 표현식 
Car car = (i) -> i == 0 ? "" : "자동차가 " + driveLevel + " 의 속도로 이동";
System.out.println(car.drive(10));

함수형 프로그래밍

함수를 하나의 값으로 취급(일급 객체)해서, 함수들을 조립하고 배치하면서 개발할 수 있는 장점이 있습니다.
(람다 표현식은 함수형 인터페이스를 위해 등장했다고 해도 과언이 아닙니다!)
또한 기본적으로 자주 사용되는 메서드 시그니처를 품고 있는 함수형 인터페이스는 java.util.function 패키지에 이미 정의되어 있습니다. 이를 활용하면 중복된 코드도 줄이고 다른 개발자와 의사소통도 편하게 할 수 있습니다.

Default method(디폴트 메서드)

인터페이스는 기능에 대한 선언만 가능하기 때문에, 실제 코드를 구현한 로직은 포함될 수 없습니다.
하지만 Java 8 에서는 메소드 선언 시에 default를 명시하게 되면 인터페이스 내부에서도 로직이 포함된 메소드를 선언할 수 있습니다.

public interface Car {
	// 전진
	void drive();
    
    // 후진
    void reverse();
    
    // 날기 
    default void fly() {
    	System.out.println("Fly");
    }
}

이를 통해서 '하위 호환성'을 유지하고 인터페이스의 보완을 진행 할 수 있습니다.
(실제로 스프링 프레임 워크 버전 4에서 WebMvcConfigure라는 인터페이스를 구현한 클래스 WebMvcConfigurerAdapter를 사용하였지만 Java 8 에서 default 메소드가 등장 후, WebMvcConfigurerAdapter클래스는 더 이상 사용되지 않습니다.)
다만 이 방법은 인터페이스가 갖는 추상 메서드 구현의 강제성이 사라지므로 누군가와 함께 작업하는 경우라면, 왜 이렇게 했는지 꼭 인지시켜야 합니다.

Stream(스트림)

스트림은 Collection을 멋지고 편리하게 처리하는 방법을 제공하는 API입니다.

// 기존 코드
books.sort(Comparator.comparing(Book::getName));

List<String> books = new ArrayList<>();
for (Book book : books) {
	if (book.getAuthor().equals("Chancehee")) {
    	books.add(book.getIsbn());
    }
}

// 스트림 사용
List<String> books = 
	books.stream()
    	.filter(book -> book.getAuthor().equals("Chancehee"))
        .sorted(Comparator.comparing(Book::getName))
        .map(Book::getIsbn)
        .collect(Collecors.toList());

이를 통해, 스트림은 개발자가 마치 쿼리문을 작성하듯 '처리방법'을 고민하지 않고 '원하는 값'을 정하면 적절한 방법으로 처리하여 값을 돌려줍니다.
(참고, 스트림의 특징(작성 예정))

Optional(옵셔널)

옵셔널은 Java가 가지고 있는 null의 문제점을 보완하고자 등장하였습니다. (Wrapper class)

public class BookService {
	public Optional<String> getAuthorName(Book book) {
    	return Optional.ofNullable(book)
        	.map(bookObject -> bookObject.getAuthor())
            .map(authorObject -> authorObject.getName());
    }
}

이를 통해 비즈니스 코드와 null 방어 코드가 뒤섞이지 않는 다는 장점이 있습니다.

새롭게 추가된 날짜 API

크게 기계용 날짜 API와 사람용 날짜 API로 나뉩니다.
기계용: Instant
사람용: LocalDate, LocalTime, LocalDateTime
이를 통해, 기존에 복잡한 날짜 계산 때문에 별도의 유틸리티 클래스를 만들어 사용대신 API를 통해 쉽게 사용이 가능하다는 장점이 있습니다.

Completable Future

Java의 비동기 프로그래밍에서 Thread 클래스는 저수준의 클래스입니다. 그래서 개발자가 해줘야하는 작업이 많습니다.
반면 Future는 상대적으로 직관적이며, Thread pool도 직접 정할 수 있고 Timeout도 설정해 무작정 기다리게 되는 문제도 해결할 수 있습니다.
하지만 예외처리를 위한 API가 없어 사용자가 임의로 try - catch로 감싸야한다거나, Future의 동작을 외부에서 강제로 완료시킬 수 없습니다.거기에 Future에서 사용하는 get()은 블로킹 코드 이므로 결과값을 반환하기 전까지 대기상태가 됩니다.
이러한 문제점들을 개선한 것이 CompletableFuture 클래스 입니다.

JVM의 변화

기존의 PermGen 영역이 사라지고 대신 Metaspace 영역이 생겼습니다.
PermGen 영역은 클래스의 메타정보를 관리하는 메모리 공간입니다. 클래스의 이름, 어노테이션 정보, static 필드 등 클래스를 구성하는 정보를 담습니다. Java 8 이전에는 PermGen 영역이 Heap 메모리에 포함되어 있어 크기가 제한되었습니다. 그래서 클래스가 많은 애플리케이션을 구동하다 보면 PermGen 영역의 OOM(Out Of Memory)이 발생하는 경우가 종종 있었습니다.
Java 8 부터는 이 공간이 삭제되고 동일한 기능을 하는 Metaspace 영역이 새롭게 생겼습니다.(Heap 대신 Native로)
Metaspace는 영역이 가변적으로 늘어나는 특징이 있습니다.
(Metaspace는 가변적으로 늘어나므로 최댓값 설정은 반드시 해주길 권장합니다. 극단적인 상황에는 서버의 모든 메모리를 MetaSpace가 가져가 애플리케이션이 아닌 서버가 죽게 될 수도 있기 때문입니다.)

3. Java 11 특징

String 클래스에 새로운 메소드 추가

6가지 메소드가 추가 되었습니다.

  • strip(): 문자열 앞, 뒤의 공백 제거
  • stripLeading(): 문자열 앞의 공백 제거
  • stripTrailing(): 문자열 뒤의 공백 제거
  • isBlank(): 문자열이 비어있거나, 공백만 포함되어 있을 경우 true 반환 (= String.trim().isEmpty())
  • repeat(n): n개 만큼 문자열을 반복하여 붙여서 반환

java.nio.file.Files 클래스에 새로운 메소드 추가

3가지 메소드가 추가 되었습니다.

  • path writeString(Path, String, Charset, OpenOption): 파일에 문자열을 작성하고 Path로 반환
  • String readString(Path, Charset): 파일 전체 내용을 읽어서 String으로 반환하고, 파일 내용을 모두 읽거나 예외가 발생하면 알아서 close
  • boolean isSameFile(Path, Path): 두 Path가 같은 파일을 가리키며, true, 아니면 false를 반환

컬렉션 인터페이스에 새로운 메소드 추가

컬렉션의 toArray() 메소드를 오버 로딩하는 메소드가 추가되었고, 원하는 타입의 배열을 선택하여 반환할 수 있게 되었습니다.

String[] arr = list.toArray(String[]::new);

Predicate 인터페이스에 새로운 메소드 추가

Predicate 인터페이스에 부정을 나타내는 not() 메소드가 추가되었습니다.

람다에서 로컬 변수 Var 사용

람다식에서 Var 변수를 사용할 수 있습니다.
(컴파일러 단에서 데이터타입 추론)

자바 파일 실행

javac를 통해 컴파일 하지 않고도, 바로 java 파일을 실행할 수 있습니다.

// Java 11 이전
$ javac HelloWorld.java
$ java HelloWorld

// Java 11 이후
$ java HelloWorld.java

4. 결론

Java 버전 중 가장 사용층이 많은 8버전, 11버전에 대해 살펴봤습니다.
Java 언어에서 가장 핵심적인 기능이 나와 'Modern Java'라고 부르는 8버전, 8버전의 사용층을 역전한 11버전
둘은 검증이 된 안정적인 버전이라고 할 수 있습니다. 개발을 하기에 앞서서 기술스택을 정할 때, 안정적인 서비스를 개발하기 위해서 내가 사용하려는 기술스택의 특징을 파악하고 사용하는 것은 나중에 문제를 발생시키지 않는 기반이라고 생각합니다.

0개의 댓글