개발 일지/Java

[Java] Java 8 / Java 11 버전 별 특징

배발자 2022. 12. 17.
반응형

 

오늘 포스팅 할 얘기는 Java 8 / Java 11 변화에 대해서 포스팅하려고 한다. 

Java 9, 10, 12, 13, 14 ......  등 이런 버전들도 많지만 왜 "8, 11" 이냐????? 

 

먼저 Java 8 / Java 11은 LTS 버전이다

 

LTS란? 

 

LTS(Long Term Support)는 말 그대로 장기 지원되는 버전을 의미한다. 

출시 후 8년 동안 업데이트 및 버그 수정을 지원하고 일반 버전과 달리 안정성에 중점을 둔 버전으로 기능 업데이트는 최소한으로 이루어지거나 아예 없는 반면, 보안 업데이트의 지원이 일반 버전보다 훨씬 길다. 

그렇기 때문에 서버 등 최신 기능보다 안정성이 중요한 곳에서 많이 쓰이며 기업이나 기관 등에서 기능 업데이트로 인해 이용 중인 다른 소프트웨어가 영향을 받는 것을 피하기 위해 이용하기도 한다. 

 

Java 8

 

람다 표현식

 

람다는 함수를 하나의 표현식으로 나타낸 것이다. 

 

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

thread.start();


// 람다 표현식
Thread thread = new Thread(() -> System.out.println("Start to new thread!"));
thread.start();

 

함수형 인터페이스 

 

단 하나의 추상 메서드를 갖는 인터페이스를 함수형 인터페이스라고 한다. 

위의 예제로 사용했던 Runnable 인터페이스는 추상 메서드 run() 하나만 있기 때문에 함수형 인터페이스라고 한다. 

@FunctionalInterface 애노테이션이 존재하는데 컴파일 시점에서 확인 할 수 있도록 하는 애노테이션이다. 

 

간단하게 만들어 보자. 

@FunctionalInterface
public interface Car {
	String drive(int speed); 
}

함수형 인터페이스를 하나 생성한다. 

 

Car car = new Car() {
    @Override
    public String drive(int speed) {
        return "이 자동차는 " + speed+"의 속도로 전진한다.";
    }
}; 
System.out.println(car.drive(5));

 

java 8 이전에는 위와 같이 익명 클래스를 구현하여 사용했다. 

하지만 java 8 에서는 람다 표현식이 가능해지면서 더욱 간단하게 사용이 가능하다.

 

Car car = (speed) -> "이 자동차는 " + speed+"의 속도로 전진한다."; 
System.out.println(car.drive(5));

 

함수형 인터페이스는 추상메서드가 딱 하나 존재하는 인터페이스이기 때문에 파라미터로 전달받을 메서드는 딱 하나이다. 그래서 위와 같이 -> 화살표를 활용하여 손쉽게 표현할 수 있다. 

 

즉, Java 8에서 람다 표현식은 함수형 인터페이스를 위해 등장했다고 해도 과언이 아니다. 

 

Default method 

 

인터페이스는 기본적으로 구현체가 없는 껍데기라는 것을 다들 알고 있을 것이다. 

하지만 자바 8에서부터 인터페이스 메서드 내부에 구현체를 만들 수 있다. 

public interface Car {
	
	String drive(int speed); 
	
	default void direction(String msg) {
		System.out.println(msg);
	}
}

 

default 키워드를 사용하면 메서드 내에 구현 코드를 작성할 수 있다. 

근데 이게 어떨 때 유용하게 쓰일까 생각해볼 수 있다. 

 

보통 인터페이스를 생성하고 나면 다른 클래스에서 implements 해서 인터페이스 껍데기 메서드를 구현코드로 채워넣야한다.  "Add unimplemented methods" 문구를 본 적이 있을 것이다. 

 

만약에 Car 를 구현한 클래스 객체가 100개가 있다고 가정하자. 

그리고 Car 인터페이스에 "저는 차에요!" 라는 문구를 구현체로 들고있는 Msg() 메서드를 하나 추가하려고 한다. 

 

만약 빈 껍데기인 Msg() 메서드를 생성한다면 100개의 클래스에선 Msg() 메서드를 오버라이딩해야한다. 

하지만 default method 로 설정해준다면 인터페이스 내에 구현체를 생성할 수 있으므로 100개의 클래스에서는 오버라이딩 없이도 새로운 기능을 추가할 수 있게 된다. 

 

즉, 코드 호환성 유지가 가능. 

 

Stream(스트림) 

 

스트림은 Collection(컬렉션)을 편리하게 처리하는 방법을 제공하는 API 이다. 

먼저 예부터 살펴보자 

 

해당 코드는 정리가 잘 되어있는 기술 블로그를 참조하였다. (출처는 하단 참고) 

 

<요구사항> 

"책들 중 니체가 작성한 책의 ISBN 정보가 필요하다. 정렬은 책 이름을 기준"

 

기본적으로 스트림을 사용하지 않고 쓴 코드는 아래와 같다. 

books.sort(Comparator.comparing(Book::getName));

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

먼저 books 에 대한 정보를 이름으로 정렬을 하고 저자가 니체인지 아닌지를 if문을 통해 검사를 해야한다. 

하지만 이러한 코드 내용이 어떤 요구사항을 구현한 것인지 가독성이 좋지만은 못하다. 

위의 코드를 스트림으로 변경해보자. 

 

List<String> booksWrittenByNietzsche = 
            books.stream()
                .filter(book -> book.getAuthor().equals("Friedrich Nietzsche"))
                .sorted(Comparator.comparing(Book::getName))
                .map(Book::getIsbn)
                .collect(Collectors.toList());

 

스트림을 통한 코드 방식은 위와같다. 

한 줄씩 읽어보면 니체이름을 가진 -> 이름으로 정렬을 해서 -> Isbn을  -> 리스트로!

 

즉, 스트림은 for문과 if문 키워드를 사용하지 않고 가독성이  한결 나아진 것이 보인다. 

 

https://steady-coding.tistory.com/598

 

컬렉션의 저장요소를 하나씩 참조해서 람다식으로 처리할 수 있도록 해주는 내부 반복자

 

 

Optional Class

 

Optional은 Java가 가지고 있는 null의 문제점을 보완하기 위해 등장했다. 

null 이 될 수 있는 객체를 담는 클래스이며 명시적으로 반환값이 Null 일 수 있음을 알려주고 직접 null을 다루지 않아도 된다. 

 

// Java 8 이전
public String logic() {
    User user = getUser();
    if (user != null) {
        Address address = user.getAddress();
        if (address != null) {
            String street = address.getStreet();
            if (street != null) {
                return street;
            }
        }
    }
    return "not specified";
}

// Java 8 이후
public String logic() {
    Optional<User> user = Optional.ofNullable(getUser());
    String result = user
      .map(User::getAddress)
      .map(Address::getStreet)
      .orElse("not specified");
    return result;
}

 

 

Java 11

 

GC 의 변화 

 

Java8 에서는 Parallel GC가 기본 GC 로 사용되다가 Java 9부터는 G1 GC가 기본 GC로 채택되었다.

추후 GC에 대한 포스팅을 할 예정이다. 

 

람다 파라미터로 Var 사용

 

(var a, var b) -> a + b; // 가능
(var a, b) -> a + b; // 불가능 - b도 var을 붙여야 함.
(var a, String b) -> a + b; // 불가능 - 타입 혼용 불가

 

람다는 기본적으로 타입을 스킵할 수 있지만 @Nullable 등의 어노테이션을 사용하기 위해 타입 명시가 필요할 때 사용한다. 괄호로 묶어야 하며 다른 타입과 혼용이 불가능하다. 

 

 

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

 

6가지 메서드가 추가되었다. 

 

strip(): 문자열 앞, 뒤의 공백 제거 

stripLeading() : 문자열의 앞의 공백 제거 

stripTrailing(): 문자열 뒤의 공백제거

isBlank(): 문자열이 비어있거나, 공백만 포함되어 있을 경우 true 반환 

repeat(n) : n개만큼 문자열을 반복하여 붙여서 반환

 

HTTP Client

 

Java 9에 도입된 HTTP 클라이언트가 표준 기능이 되었고 HTTP/1.1 , HTTP/2 를 지원한다. 

 


 

현재 기업을 보면 Java 8과 Java 11을 주로 채택하여 사용하고 있는데, 아마 Java 8을 선호하는 이유는 자바 역사를 통틀어 가장 큰 변화가 자바 8에서 일어났고 스트림 API 와 인터페이스 디폴트, 람다 등 유용하고 간편한 새로운 기술들이 많이 도입되었다고 생각한다. 즉, 자바 8은 프로그램을 더 효과적이고 간결하게 구현할 수 있는 새로운 개념과 기능을 제공하였다. Java 11에서는 Java 8의 기능을 수용하면서 더 나은 라이브러리가 추가되고 성능이 개선된 G1 GC를 사용한다. 이러한 측면에서 Java 11을 채택하여 프로젝트를 경험한 바가 있다. 

 

 

 

 

반응형

'개발 일지 > Java' 카테고리의 다른 글

[Java] 해시 충돌  (0) 2022.12.19
[Java] equals 와 hashCode  (0) 2022.12.18
[Java] public static void main 인 이유?  (0) 2022.12.18
[Java] ArrayList 동작원리  (0) 2022.12.17
[JAVA] JVM 구조와 JAVA의 동작 원리  (0) 2022.01.16

댓글