BackEnd/Java

Java 9. 주요 변경 내용 (1)

hanseom 2024. 12. 3. 22:00
반응형

try-with-resources 확장

  try-with-resources는 Java 7에서 추가된 기능으로 개발자가 직접 닫아줘야 하는 자원을 try() 안에 선언하면, try 로직이 끝난 후 자동으로 해당 자원을 닫아주는 것입니다. 자동으로 해당 자원을 닫아주기 위해서는 AutoCloseable을 구현하고 있어야 합니다.

 

  • Java 7 이전 코드
Resource resource = new Resource();
try {
  // 작업
} finally {
  resource.close();
}

 

  • Java 7 이후 코드
try (Resource resource = new Resource()) {
  // 작업
}

 

  Java 7의 try-with-resources의 경우, try() 밖에서 만든 자원을 닫을 수는 없습니다.

Resource r1 = new Resource("r1");
try (
  r1; // Compile Error !!
  Resource r2 = new Resource("r2")
) {
  // Logic
}

 

  Java 9에서는 이를 개선하여 try 바깥의 final 변수 or 사실상 final인 변수(한 번 선언된 후 변경이 되지 않은)도 자동으로 자원을 닫아줍니다.

Resource r1 = new Resource("r1");
final Resource r2 = new Resource("r2");
try (r1; r2) {}

 

@SafeVarargs 어노테이션 확장

  @SafeVarargs는 Java 7에서 도입된 어노테이션으로, 제네릭 가변인수(varargs) 메소드의 타입 안전성을 보장하는 데 사용됩니다. Java 9 이전에는 @SafeVarargs 어노테이션을 final 메소드, static 메소드, 생성자에만 사용할 수 있었습니다. Java 9부터는 private 메소드에도 해당 어노테이션을 사용할 수 있게 되었습니다.

 

  가변인수(varargs)란 메소드를 호출할 때 매개변수의 개수를 자유롭게 넣을 수 있는 것으로, 내부적으로 해당 값들이 담겨 있는 배열이 생성됩니다.

public static int sum(int... nums) {
  return Arrays.stream(nums).sum();
}

 

  제네릭 함수에서 가변인수를 사용하면 안전하지 않을 수 있다는 경고가 발생합니다. @SafeVarargs를 사용하면 메소드 호출 시 발생하는 경고를 억제할 수 있어, 코드의 가독성을 높이고 불필요한 경고를 제거할 수 있습니다.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {
  
  @SafeVarargs
  public static <T> List<T> flatten(List<T>... lists) {
    List<T> result = new ArrayList<>();
    for (List<T> list : lists) {
      result.addAll(list);
    }
    return result;
  }
  
  public static void main(String[] args) {
    List<Integer> list1 = Arrays.asList(1, 2, 3);
    List<Integer> list2 = Arrays.asList(4, 5);
    List<Integer> result = flatten(list1, list2);
    System.out.println(result);
  }
}

 

익명 inner class + diamond syntax

  Java 9부터는 내부 클래스를 익명 클래스로 만들 때 diamond syntax 사용이 가능해졌습니다. diamond syntax란 제네릭 클래스를 인스턴스화 할 때 우항(오른쪽)의 타입을 생략할 수 있는 것입니다.

// 타입을 생략하지 않음
List<Integer> numbers1 = new ArrayList<Integer>();

// 타입을 생략함 (diamond syntax)
List<Integer> numbers2 = new ArrayList<>();

 

  내부 클래스는 외부 참조를 할 수 있는 내부 클래스와 외부 참조를 할 수 없는 내부 클래스가 있습니다. 외부 참조가 있으면 메모리 관리가 어렵고, 직렬화 표준도 없기 때문에 외부 참조가 없는 내부 클래스가 권장됩니다.

public class Main {
  // 외부 (Main) 참조를 할 수 있는 내부 클래스
  public class ReferenceClass { }
  
  // 외부 (Main) 참조를 할 수 없는 내부 클래스
  public static class NoReferenceClass { }
}

 

  다음은 Java 9부터 내부 클래스를 익명 클래스로 만들 때 diamond syntax를 적용한 코드입니다.

public class Main {

  public static void main(String[] args) {
    InnerClass<Integer> ic = new InnerClass<>(3) { // diamond syntax
    };
    int _abc = 3;
  }
  
  public static class InnerClass<T> {
    private final T t;
    public InnerClass(T t) {
      this.t = t;
    }
  }
}

 

인터페이스 + private 메소드

  Java 8부터는 인터페이스에 default 메소드를 구현할 수 있게 되었습니다. 그러나 default 메소드를 구현 하다 보니 로직이 겹치는 코드가 발생하기 시작하였습니다. Java 9에서는 중복된 코드를 제거하고 재사용성 향상을 위해 인터페이스에도 private 메소드를 사용 가능하게 되었습니다.

public interface PaymentProcessor {
    
    default void processPayment(double amount) {
        if (validateAmount(amount)) {
            System.out.println("Processing payment of $" + amount);
            sendConfirmation();
        } else {
            System.out.println("Invalid payment amount");
        }
    }
    
    default void refundPayment(double amount) {
        if (validateAmount(amount)) {
            System.out.println("Refunding payment of $" + amount);
            sendConfirmation();
        } else {
            System.out.println("Invalid refund amount");
        }
    }
    
    // Private helper method
    private boolean validateAmount(double amount) {
        return amount > 0;
    }
    
    // Private helper method
    private void sendConfirmation() {
        System.out.println("Sending confirmation email...");
    }
    
    // Static private method
    private static void logTransaction(String type, double amount) {
        System.out.println("Logging " + type + " transaction: $" + amount);
    }
    
    // Public static method that uses private static method
    static void auditPayment(double amount) {
        logTransaction("payment", amount);
    }
}

 

underscore 네이밍 불가능

  Java 9에서는 언더스코어(_)를 변수 이름으로 사용하는 것이 불가능하게 되었습니다. 이는 언더스코어가 Java 9부터 예약된 키워드로 지정되었기 때문입니다. 해당 변경은 언더스코어를 향후 Java 버전에서 특별한 의미를 가진 키워드로 사용하기 위한 준비 단계입니다.

반응형