[Java] 자바의 버전별 기능

유아 Yooa·2023년 5월 23일

Java

목록 보기
1/3
post-thumbnail

원문 - Java version and features
Java 버전별 차이점을 이해하고, Java 언어를 이해해보자.
내가 알고싶은 내용에 살을 붙여서 써놓음. 보다 풍부한 내용은 원문을 보러가자.
틀린 내용에 대해서는 댓글로 사랑을 쏴주자.

Overview

최신 Java 버전


Java는 6개월마다 업데이트 된다.

  • 2023년 3월 기준, Java 20은 최신 릴리스
  • 2023년 9월 Java 21이 릴리스될 것
  • 현재 Java의 LTS(Long Term Support)는 2021년 9월 출시된 Java 17

8과 같은 일부 Java 버전이 1.8이라고 하는 이유

  • Java 9 이전 버전에서는 다른 이름 지정 체계가 있었기 때문
  • Java 8을 1.8, Java 5을 1.5 등으로 불렸음
  • Java 9 이후에는 명명 체계가 변경되어 1.x 접두사가 붙지 않음.

Java 버전간의 차이점

  • Java는 이전 버전과 호환된다.
  • Java 8은 모든 언어에서 좋은 기반 역할을 한다.
  • Java 9-20이 어떤 추가 기능이 있는지를 알아보고 사용하면 된다.
  • 6개월 릴리스 주기이므로 그만큼 적은 기능이 업데이트되므로 9-20 버전의 기능을 빠르게 학습할 수 있을 것

JRE와 JDK의 차이점

  • JRE(Java Runtime Environment)
    - Java 프로그램 실행
    • JVM(Java Virtual Machine)과 "java" 명령어 도구 포함
  • JDK(Java Development Kit)
    - 새로운 Java 프로그램 개발
    • JRE에 있는 모든 것, Compiler javac 및 Javadoc(Java documentation generator) 및 jdb(Java Debugger)와 같은 기타 도구 포함
  • Java 8까지는 Oracle 웹 사이트에서 JRE와 JDK를 별도의 다운로드로 제공했다.
    - 명시적인 JRE 폴더가 포함되어 있다.
  • Java 9에서는 이러한 구분이 사라지고 항상 JDK를 다운로드한다.
    - 명시적인 JRE 폴더가 없다.
  • 여전히 JRE 다운로드를 제공하고 있긴 하지만 JDK만 제공하는 추세이다.

Java 또는 JDK를 설치하는 방법

  • jdk-{5-20}.zip 파일의 압축을 풀기만 하면 된다.
  • 압축을 풀고 /bin 디렉토리를 PATH 변수에 넣는다.
    - 그러면 java 명령어를 어느 위치에서든 호출할 수 있다.
  • java -version을 실행하면 버전이 출력된다.

Java Features 8-20

  • Java 8 기능은 Java 20에서도 작동한다. (그 사이의 모든 Java 버전도 마찬가지)

    Java 8의 모든 기능은 매우 우수한 Java 기본 지식으로 사용되며 다른 모든 버전(Java 9-20)은 해당 기준에 추가되는 추가 기능이다.

Java 8

  • Java 8은 대규모 릴리스였으며 Oracle 사이트에서 모든 기능 목록을 확인할 수 있다.

Java 8 : lambda

  • Java 8 이전에는 새 Runnable를 인스턴스화할 때마다 익명 클래스를 작성해야 했다. (익명 구현 객체)
 Runnable runnable = new Runnable(){
       @Override
       public void run(){
         System.out.println("Hello world !");
       }
     };

lambda를 사용하면 동일 코드를 다음과 같이 표현할 수 있다.

Runnable runnable = () -> System.out.println("Hello world two!");

Java 8 : Collection과 Stream

  • Java 8에서는 Stream API라고 하는 Collection에 대한 functional-style operations이 제공된다.
List<String> list = Arrays.asList("franz", "ferdinand", "fiel", "vom", "pferd");
  • Java 8 이전에는 해당 리스트에서 작업을 수행하려면 for-loop를 작성해야 했다.
    - 로직이 복잡해질수록 코드의 양이 많아져 여러 로직이 섞이게 되는 경우 발생
  • Stream API를 사용하면 다음과 같이 수행할 수 있다.
list.stream()
    .filter(name -> name.startsWith("f"))
    .map(String::toUpperCase)
    .sorted()
    .forEach(System.out::println);

Java 9

Java 9 : Collections

  • Collection에는 List, Set, Map을 쉽게 구성할 수 있는 새로운 helper method(of)가 있다.
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");

Java 9 : Streams

  • Streams에는 takeWhile, dropWhile, iterate method가 추가됐다.
Stream<String> stream = Stream.iterate("", s -> s + "s")
  .takeWhile(s -> s.length() < 10);
  1. takeWhile()
  • 조건에 대해 참이 아닐 경우 바로 멈춘다.
  • 이미 정렬되어 있다면 false가 등장한 위치부터 반복을 중단할 수 있기 때문에 크기가 큰 Stream의 경우 많은 시간을 절약할 수 있다.
List<Integer> takeWhileList = numbers.stream()
                                        .takeWhile(i -> i < 50)
                                        .collect(toList()); // 12, 17, 29, 35, 41, 44
  1. dropWhile()
  • takeWhile의 정반대 작업으로 처음으로 false가 등장하는 시점까지의 요소를 모두 버리고 남은 요소를 반환한다.
List<Integer> dropWhileList = numbers.stream()
                                        .dropWhile(i -> i < 50)
                                        .collect(toList()); // 50, 66, 72, 80
  1. iterate()
  • Java 8부터 있던 Stream 클래스의 iterate() 메서드를 overload한 신규 메소드
  • 어떤 연산을 반복적으로 수행할 때 사용되는 메서드
  • 명령형 프로그래밍(imperative programming)에서 for나 while과 같은 루프문으로 해결하던 코드를 함수형(functional programming) 방식으로 작성할 때 유용하게 사용한다.

3-1. Java 8의 iterate()

int sum = Stream.iterate(0, i -> i + 1)
  .filter(i -> i % 2 == 1)
  .limit(5)
  .mapToInt(Integer::intValue)
  .sum();
System.out.println("합: " + sum); // 합: 25
  • 초기 값 0에서 1이 증가되는 값들을 담고 있는 스트림에서 홀수값을 처음 5개만 남기고 unboxing 한 후 더해서 sum 변수에 할당
  • Java 8에서 iterate()는 조심스럽게 사용하지 않으면 무한 스트림을 만들어낼 수 있었기에 개발자들에게 많은 사랑을 받지 못한 듯

3-2. Java 9의 iterate()

  • 스트림 종료 조건을 인자로 받는 iterate() 메서드가 Stream 클래스에 추가되었다.
int sum = Stream.iterate(0, i -> i < 10, i -> i + 1)
  .filter(i -> i % 2 == 1)
  .mapToInt(Integer::intValue)
  .sum();
System.out.println("합: " + sum); // 합: 25
  • 초기 값 0에서 10보다 작다면 1씩 증가되는 값들을 담고 있는 스트림에서 홀수값만 남기고 언박싱(unboxing) 후 더해서 sum 변수에 할당

Java 9 : Optionals

  • ifPresentOrElse 메소드는 기존의 ifPresent() 메서드와 이름이 유사하다.
    - ifPresent()메서드는 Optional 객체가 값을 담고 있을 때 처리할 내용만 정의했다면, ifPresentOrElse() 메서드는 그와 더불어, Optional 객체가 비어있을 경우 처리할 내용까지 정의한다.
user.ifPresentOrElse(this::displayAccount, this::displayLogin);

Java 9 : Interfaces

  • 인터페이스는 private 메소드를 가질 수 있다.
public interface MyInterface {

    private static void myPrivateMethod(){
        System.out.println("Yay, I am private!");
    }
}

Java 9 : other features

개선된 try-with-resources

  1. try-with-resources(TWR)
  • try(..)에서 선언된 객체들에 대해서 try가 종료될 때 자동으로 자원을 해제해주는 기능이다.
try (BufferedReader br = new BufferedReader(new FileReader("C:\\number.txt"))) {
        String str;
        while ((str = br.readLine()) != null) {
            System.out.println(str);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

1-1. Java 7 TWR

  • Java 7 이전에, try-catch-finally 구문에서 자원을 해제하려면 코드 양이 많고 매우 지저분했다.
    - try에서 객체를 생성하고, try 안의 코드에서 Exception이 발생하는 경우 모든 코드가 실행되지 않을 수 있으므로 fianlly에서 close() 코드를 넣어주고...
  • Java 7 부터 TWR 구문을 지원하고 자원을 쉽게 해제할 수 있다.
    - try(...)안에 객체 선언 및 할당을 해주면 try 문에서 사용할 수 있다.
    • 코드의 실행 위치가 try 문을 벗어나면 TWR는 선언된 객체에 대한 close() 메소드를 호출한다.
    • finally에서 명시적으로 close()를 호출해줄 필요가 없다.
  • 모든 객체의 close()를 호출해주지는 않고, AutoCloseble을 구현한 객체만 close()가 호출된다.

1-2. Java 9 TWR

  • Java 7의 TWR은 자원 할당을 try 밖에서 하면 그 변수를 가지고 바로 try 문 안에서 바로 사용할 수는 없었다.
    - 따로 try 안에서 새로운 변수를 선언하여 사용해야 했다.
 BufferedReader brs = new BufferedReader(new FileReader("C:\\number.txt"));
        try (BufferedReader br = brs) {
            String str;
            while ((str = br.readLine()) != null) {
                System.out.println(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
  • Java 9에서는 그럴 필요가 없고, 세미콜론을 이용해서 복수개의 변수를 가질 수도 있다.
BufferedReader br = new BufferedReader(new FileReader("C:\\number.txt"));
        BufferedReader br2 = new BufferedReader(new FileReader("C:\\abc.txt"));
        try (br; br2) {
            String str;
            while ((str = br.readLine()) != null) {
                System.out.println(str);
            }
            while ((str = br2.readLine()) != null) {
                System.out.println(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
  • 주의점은 사용할 변수가 final이거나 effectively final(초기화 된 이후 절대 바뀌지 않는 변수)이어야 한다는 점이다.

Diamond Operator 확장

  • 익명 객체를 생성할 때도 다이아몬드 연산자를 사용할 수 있다.
Function<Integer, Integer> function = new Function<>() {
    @Override
    public Integer apply(Integer input) {
        return input * 3;
    }
};

Java 9 : JShell

  • Java에는 간단한 명령을 시도하고 즉각적인 결과를 얻을 수 있는 셸이 있다.
% jshell
|  Welcome to JShell -- Version 9
|  For an introduction type: /help intro

jshell> int x = 10
x ==> 10

Java 9 : HTTP 클라이언트

  • Java 기본 제공 Http 지원은 낮은 수준이었고 Apache HttpClient 또는 OkHttp와 같은 타사 라이브러리를 사용해야 했다.
  • Java 9에는 Java의 자체적인 최신 클라이언트가 있다. 초기 preview 버전이지만 이후 버전에서 변경될 수 있음을 의미한다.

Java 10

Java 10 : 지역 변수 타입 추론 - var-keyword

  • Java 10에서 도입된 var은 변수를 선언할 때 타입을 생략할 수 있으며, Complier가 타입을 추론한다.
var string = "Hello, World";
  • Compiler가 String 타입을 추론하여 변수에 타입을 지정해준다.
    - 타입을 추론할 수 없는 애매한 상황일 때 컴파일 에러가 발생한다.
  • 컴파일 타임에 추론하는 것이기 때문에, Runtime에 추가 연산을 하지 않아 성능에 영향을 주지 않는다.
  • 메서드 내부의 변수에만 적용된다.
  • 초기화를 하지 않으면 어떤 타입인지 추론할 수 없기 때문에 컴파일 에러가 발생한다.
    - null로 초기화할 수 없고, 배열에 사용할 수 없다.
    • lambda에도 사용할 수 없다.

Java 11

Java 11 : String과 File

  • 문자열과 파일에서 새로운 메서드가 생겼다. 모든 기능 목록을 명시한 것은 아님!
"Marco".isBlank();
"Mar\nco".lines();
"Marco  ".strip();

Path path = Files.writeString(Files.createTempFile("helloworld", ".txt"), "Hi, my name is!");
String s = Files.readString(path);

java.lang.String 클래스의 메소드

1-1. isBlank()

  • 문자열이 비어 있거나, 빈 공백으로만 이루어져 있으면 true를 리턴한다.

1-2. strip()

  • 문자열 앞, 뒤의 공백을 제거한다.

    stripLeading(): 문자열 앞의 공백을 제거한다.
    stripTrailing(): 문자열 뒤의 공백을 제거한다.

  • trim()은 U+0020 이하의 값만을 공백으로 인식하여 제거(tab, CR, LF, 공백)하여 유니코드에서의 다양한 공백 문자를 처리할 수 없었다. Java 11 부터는 strip()으로 편하게 처리하고 성능도 수 배 빨라졌다.

1-3. lines()

  • 문자열을 라인 단위로 쪼개는 스트림을 반환한다.

1-4. repeat(n)

  • 지정된 수 만큼 문자열을 반복하여 붙여 반환한다.
String str = "ABC";
String repeated = str.repeat(3);	// "ABCABCABC"

java.nio.file.Files 클래스의 유틸 메소드

2-1. Path writeString(Path, String, Charset, OpenOption)

  • 파일에 문자열을 작성하고 Path로 반환한다.
  • 파일 오픈 옵션에 따라 작동 방식을 달리한다.
  • charset을 지정하지 않으면 utf-8을 사용한다.

2-2. String readString(Path, Charset)

  • 파일 전체 내용을 읽어서 String으로 반환한다.
  • 파일 내용을 모두 읽거나 예외가 발생하면 close 한다.
  • charset을 지정하지 않으면 utf-8이 사용된다.

2-3. boolean isSameFile(Path, Path)

  • 두 Path가 같은 파일을 가리키면 true, 아니면 false를 반환한다.
  • 파일이 실제로 존재하지 않아도, Path를 기준으로 해서 같은 위치면 true로 판단한다.

Java 11 : 소스 파일 실행

  • Java 10부터 컴파일하지 않고도 Java 소스 파일을 실행할 수 있었다.
~$ java MyScript.java

Java 11 : 람다 매개변수로 var 사용

  • Java 8에 등장했으나 10 버전에서 사라졌다가 Java 11에서 복귀한 기능
  • 람다에서 타입을 스킵할 수 있는데 이걸 사용하는 이유는 @Nullable 등의 어노테이션을 사용하기 위해 타입을 명시해야 할 때
  • var를 사용하려면 괄호를 써야하며, 모든 파라미터에 사용해야 하고, 다른 타입과 혼용하거나 일부 스킵은 불가능하다.
(var firstName, var lastName) -> firstName + lastName

Java 11 : Http 클라이언트

  • preview가 아닌 최종의 Java 9의 Http Client

Java 11 : etc

  • Flight Recorder, No-Op Garbage Collector, Nashorn-Javascript-Engine deprecated 등

Java 12

  • Unicode 11 지원
  • Switch Expression preview

Java 13

  • Unicode 12.1 지원

Java 13 : 개선된 Switch Expression Preview

  • Switch 식은 값을 반환할 수 있다.
  • fall-through/break 문제 없이 표현식에 람다 스타일 구문을 사용할 수 있다.
boolean result = switch (status) {
    case SUBSCRIBER -> true;
    case FREE_TRIAL -> false;
    default -> throw new IllegalArgumentException("something is murky!");
};

Java 13 : 여러 줄 문자열 Preview

String htmlBeforeJava13 = "<html>\n" +
              "    <body>\n" +
              "        <p>Hello, world</p>\n" +
              "    </body>\n" +
              "</html>\n";

String htmlWithJava13 = """
              <html>
                  <body>
                      <p>Hello, world</p>
                  </body>
              </html>
              """;

Java 14

Java 14 : Switch Expression Standard

int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY                -> 7;
    default      -> {
      String s = day.toString();
      int result = s.length();
      yield result;
    }
};

Java 14 : record Preview

  • data, getter/setter, equals/hashcode, toString만 포함하는 record 클래스
final class Point {
    public final int x;
    public final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

// 레코드를 사용하면?
record Point(int x, int y) { }

Java 14 : Helpful NullpointerExceptions

  • NullPointerExceptions는 정확히 어떤 변수가 null 인지 설명한다.
author.age = 35;
---
Exception in thread "main" java.lang.NullPointerException:
     Cannot assign field "age" because "author" is null

Java 14 : InstanceOf에 대한 패턴 일치 Preview

  • 일반적으로 instanceof 연산자 다음에 cast를 사용하여 작업을 수행해야 했다.
    - 캐스팅 및 변수 추출이 늘어나며 가독성이 떨어진다.
    • 유형 이름을 반복적으로 선언하면 오류가 발생할 가능성이 높아진다.
if (animal instanceof Cat) {
    Cat cat = (Cat) animal;
    cat.meow();
   // other cat operations
}
  • Java 14는 매개 변수를 테스트하고 적절한 유형의 바인딩 변수에 할당하는 개선된 버전의 instanceof 연산자를 제공한다.
if (obj instanceof String s) {
    System.out.println(s.contains("hello"));
}

Java 14 : 패키징 툴

  • 필요한 모든 dependency를 포함해 Java 어플리케이션을 플랫폼별 패키지로 패키징할 수 있는 인큐베이팅 jpackage 도구가 있다.
  • linux : deb과 rpm
  • macOS : pkg과 dmg
  • window : msi과 exe

Java 14 : Garbage Collectors

  • CMS(Concurrent Mark Sweep) Garbage Collector가 제거되고 실험적인 ZGC(Z Garbage Collector)가 추가되었다.
  • ZGC는 확장 가능한 지연을 줄인 Garbage Collector
    - ZGC는 10ms 이상 애플리케이션 스레드 실행을 중단하지 않고 비용이 많이 드는 모든 작업을 동시에 수행하므로 짧은 대기 시간이 필요하거나 매우 큰 힙(멀티 테라바이트)을 사용하는 애플리케이션에 적합하다.

Java 15

Java 15 : 텍스트 블록/여러 줄 문자열

  • Java 13에서 실험적 기능으로 도입된 여러 줄 문자열이 실제 제품 단계 수준이 되었다.
String text = """
                Lorem ipsum dolor sit amet, consectetur adipiscing \
                elit, sed do eiusmod tempor incididunt ut labore \
                et dolore magna aliqua.\
                """;

Java 15 : Sealed Classes Preview

  • Sealed Class, Interface는 간단하게 상속하거나, 구현할 클래스를 지정해두고 해당 클래스들만 상속, 구현을 허용하는 키워드이다.
public abstract sealed class Shape
    permits Circle, Rectangle, Square {...}
  • 허용한 클래스를 제외한 다른 클래스가 구현하려고 하면 에러를 발생시킨다.

Java 15 : record와 패턴 일치

  • Java 14 기능인 Records와 Pattern Matching은 아직 Preview 상태이며 완료되지 않았다.

Java 15 : Nashorn 자바스크립트 엔진

  • Java 11에서 더 이상 사용되지 않는 Nashorn Javascript 엔진이 제거되었다.

Java 15 : ZGC production-ready

  • 실험용의 ZGC가 아닌 production-ready가 되었다.

Java 16

Java 16 : InstanceOf에 대한 패턴 일치

if (obj instanceof String s) {
    // Let pattern matching do the work!
    // ... s.substring(1)
}

Java 16 : Unix 도메인 소켓 채널

  • Unix 도메인 소켓에 연결할 수 있다. macOS와 Windows(10+)에서도 지원된다.
 socket.connect(UnixDomainSocketAddress.of(
        "/var/run/postgresql/.s.PGSQL.5432"));

Java 16 : Foreign Linker API Preivew

  • 다른 프로그래밍 언어로 작성된 라이브러리 및 외부 메모리에 액세스하기 위해서 지금까지 Java는 JNI(Java Native Interface)로 제공했다.
    - JNI를 사용하면 어플리케이션에 C/C++나 Java와 같은 프로그래밍 언어로 작성된 Native code가 포함될 수 있다.
  • JNI(Java Native Interface)에 대한 계획된 대체품으로 native library에 바인딩할 수 있다.

Java 16 : record와 패턴 일치

  • 두 기능 모두 production-ready가 되어 in preview가 표시되지 않는다.

Java 16 : Sealed Classes

  • 아직 preview 상태이다.

Java 17

  • Java 17은 Java 11 이후 새로운 LTS 릴리스이다.

Java 17 : Switch에 대한 패턴 일치 Preview

public String test(Object obj) {

    return switch(obj) {

    case Integer i -> "An integer";

    case String s -> "A string";

    case Cat c -> "A Cat";

    default -> "I don't know what it is";

    };

}

Java 17 : Sealed Classes Finalized

  • Java 15 에서 Preview로 제공된 기능이 이제 finalized

Java 17 : Foreign Function & Memory API (Incubator)

  • JNI(Java Native Interface)를 대체한다.
  • outside native finction을 호출하고 JVM의 메모리에 액세스할 수 있다.
  • 지금은 C만 지원하지만 시간이 지나면 추가 언어를 지원할 것 같다.

Java 17 : Security Manager 사용 중단

  • Java 1.0 부터의 Security Manager가 더 이상 사용되지 않으며 향후 버전에서 제거될 예정이다.

Java 18

Java 18 : UTF-8가 디폴트 인코딩

  • 이전 Java 버전에서는 OS의 인코딩이 사용되었다.
  • Java 18 에서는 UTF-8이 디폴트로 변경되었다.

Java 18 : Simple Web Server

  • Java 18에서는 간편한 설정과 최소한의 기능으로 바로 사용 가능한 정적 HTTP 파일 서버를 제공한다.
  • 다음 명령은 Simple Web Server를 시작한다.
jwebserver

Java 19

  • Virtual Threads나 새로운 Foreign Function & Memory API 그리고 Structured Concurrency, Vector API 등 몇몇 기능이 추가되었지만 이들은 모두 Preview mode이기 때문에 충분히 다음 릴리스에서 변화될 수 있다.

Java 20

  • 범위 값, 레코드 패턴, 스위치에 대한 패턴 일치, Foreign Function & Memory API, 가상 스레드 및 Structured Concurrency에 대한 작업이 진행중이며 아직 완료되지 않았다.

출처

profile
기록이 주는 즐거움

2개의 댓글

comment-user-thumbnail
2023년 9월 23일

잘 보고 갑니다. 감사합니다!

답글 달기
comment-user-thumbnail
2024년 1월 26일

이걸 작성하네 ㅋㅋㅋ 잘보고 갑니다용

답글 달기