보라코딩

try-with-resources, CompletableFuture, Optional 본문

코딩/Spring

try-with-resources, CompletableFuture, Optional

new 보라 2024. 7. 2. 21:46

 

try-with-resources

 

 

자바에서 자원을 관리하는 효율적인 방법 중 하나

이 구문을 사용하면 파일이나 네트워크 연결과 같은 자원을 자동으로 닫아주기 때문

자바 7부터 도입된 이 기능은 자원을 사용한 후에 명시적으로 닫아줘야 하는 번거로움을 줄여줌

try-with-resources는 AutoCloseable 인터페이스를 구현한 모든 객체에 사용할 수 있습니다. 왜냐하면 AutoCloseable 인터페이스에는 close() 메소드가 정의되어 있으며, try-with-resources 구문이 종료될 때 자동으로 이 메소드가 호출되기 때문입니다.

이 구문의 사용은 매우 간단합니다. try 괄호 안에 자원을 선언하면, 해당 블록의 실행이 끝나면 자동으로 자원이 닫힙니다. 왜냐하면 자바 런타임이 자동으로 close() 메소드를 호출하여 자원을 정리하기 때문입니다. 이는 코드를 더 깔끔하게 유지할 수 있게 해줍니다.

try-with-resources를 사용하면 예외 처리도 더 간단해집니다. 왜냐하면 자원을 닫는 과정에서 발생할 수 있는 예외를 자동으로 처리할 수 있기 때문입니다. 이는 개발자가 자원을 닫는 코드를 직접 작성할 때 발생할 수 있는 실수를 줄여줍니다.

이 구문의 또 다른 장점은 코드의 가독성을 향상시킨다는 것입니다. 왜냐하면 자원 관리를 위한 코드가 줄어들기 때문에, 실제 로직에 더 집중할 수 있게 해주기 때문입니다. 따라서 try-with-resources는 자바에서 자원 관리를 위한 권장되는 방법 중 하나입니다.

 

try-with-resources의 가장 큰 장점은 자원을 자동으로 안전하게 닫아준다는 것입니다. 왜냐하면 이 구문을 사용하면 개발자가 자원을 닫는 코드를 직접 작성할 필요가 없으며, 자바 시스템이 알아서 처리해주기 때문입니다. 이는 코드의 안정성을 높여줍니다.

또한, 이 구문은 예외 처리를 간소화합니다. 왜냐하면 자원을 닫는 과정에서 발생할 수 있는 예외를 자동으로 처리할 수 있기 때문입니다. 이는 코드의 복잡성을 줄이고, 개발자가 실제 로직에 더 집중할 수 있게 해줍니다.

하지만 try-with-resources를 사용할 때 주의해야 할 점도 있습니다. 왜냐하면 이 구문은 AutoCloseable 인터페이스를 구현한 자원에만 사용할 수 있기 때문입니다. 따라서 사용하려는 자원이 이 인터페이스를 구현했는지 확인해야 합니다.

또한, 여러 자원을 동시에 사용하는 경우 각 자원을 별도의 try-with-resources 문으로 관리하는 것이 좋습니다. 왜냐하면 이렇게 하면 각 자원을 개별적으로 관리할 수 있으며, 자원 간의 의존성으로 인한 문제를 방지할 수 있기 때문입니다.

결론적으로, try-with-resources는 자바에서 자원 관리를 위한 강력한 도구입니다. 왜냐하면 이 구문을 통해 자원을 효율적으로 관리하고, 코드의 안정성과 가독성을 향상시킬 수 있기 때문입니다. 따라서 자바 개발자라면 이 구문을 적극적으로 활용해야 합니다.

 

참고, 꼭 catch를 할 필요 없음!!!

 

 

출처 : https://f-lab.kr/insight/understanding-try-with-resources-in-java?gad_source=1&gad_source=1&gclid=CjwKCAjwp4m0BhBAEiwAsdc4aB1oFZKOo0zVmOGR45c6vNHSSXGt7sLlHCNhT0vExexhVJ2AMUXa6BoCTpEQAvD_BwE

 

 

 

 

 

Future

 

 

자바에서 Future는 비동기적인 작업을 처리할 수 있도록 도와주는 인터페이스입니다. Future는 작업이 완료될 때까지 기다리거나 작업의 상태를 확인하고, 작업이 완료되면 결과를 얻을 수 있는 기능을 제공합니다.


Future 내부적으로 Thread-Safe 하도록 구현되었기 때문에 synchronized block을 사용하지 않아도 됩니다.

 

  1. get(): Future 객체의 작업이 완료될 때까지 기다리고, 작업이 완료되면 결과를 반환합니다. 만약 작업이 아직 완료되지 않았다면, 이 메서드는 블록됩니다.
  2. isDone(): Future 객체의 작업이 이미 완료되었는지 여부를 확인합니다. 작업이 완료되었으면 true를 반환하고, 아직 완료되지 않았으면 false를 반환합니다.
  3. cancel(boolean mayInterruptIfRunning): Future 객체의 작업을 취소합니다. 이 메서드는 작업이 이미 시작되었거나 완료된 후에도 호출할 수 있습니다.

 

Future는 주로 ExecutorService를 사용하여 생성되며, 비동기적으로 실행되는 작업의 결과를 효율적으로 관리하고 처리할 수 있도록 도와줍니다. 다만, Future 자체는 작업의 성공 여부나 예외 처리에 대한 기능은 제공하지 않으며, 이를 보완하기 위해 CompletableFuture 와 같은 확장된 기능을 제공하는 클래스들이 있습니다.

 

 

 

 

CompletableFuture

 

 

 

 

CompletableFuture는 Java에서 제공하는 비동기 프로그래밍을 지원하기 위한 확장된 클래스입니다. 기존의 Future 인터페이스보다 더 유연하고 강력한 기능을 제공하여 비동기 작업을 보다 쉽게 다룰 수 있게 해줍니다.

 

 

주요 특징과 메서드

  1. 조합성: 여러 개의 CompletableFuture를 조합하여 복잡한 비동기 작업 흐름을 만들 수 있습니다. 예를 들어, 두 개의 CompletableFuture의 결과를 합쳐서 다른 CompletableFuture를 생성하거나, 여러 개의 CompletableFuture 중 하나라도 완료될 때까지 기다릴 수 있습니다.
  2. 콜백 지원: thenApply, thenAccept, thenCombine 등 다양한 콜백 메서드를 통해 비동기 작업이 완료된 후 실행할 작업을 지정할 수 있습니다. 이를 통해 비동기 작업의 결과를 다른 작업에 전달하거나 처리할 수 있습니다.
  3. 예외 처리: 작업 중 발생한 예외를 처리하는 exceptionally 메서드를 제공하여 예외 상황에 대한 처리를 지정할 수 있습니다.
  4. 타임아웃 설정: completeOnTimeout, orTimeout 메서드를 사용하여 작업의 완료 시간을 설정하고, 지정된 시간 내에 작업이 완료되지 않으면 예외를 발생시킬 수 있습니다.
  5. 결과 제공: complete, completeExceptionally 메서드를 사용하여 CompletableFuture에 결과나 예외를 직접 제공할 수 있습니다. 이를 통해 외부에서 CompletableFuture의 결과를 수동으로 설정할 수 있습니다.

 

 

1. 비동기로 작업 실행하기

  - 반환값이 없는 경우 : runAsync()

CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
    // 비동기 작업을 수행하는 코드
});


  - 반환값이 있는 경우 : supplyAsync()

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
    // 비동기 작업을 수행하고 결과를 반환하는 코드
    return 42;
});



  - 원하는 Executor(스레드풀)를 사용해서 실행할 수도 있다.

Executor executor = Executors.newFixedThreadPool(5);
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
    // 비동기 작업을 수행하는 코드
}, executor);


  - 기본은 ForkJoinPool.commonPool() 사용하지만 명시적으로 지정 가능

 

 


2. 콜백 제공하기

  - thenApply(Function) : 반환값(결과)을 받아서 다른 값으로 바꾼 후 그걸 반환하는 callback

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 20);
CompletableFuture<String> processed = future.thenApply(result -> "Result: " + result);

 

  - thenAccept(Consumer) : 결과를 받아 다른 작업을 반환없이 처리하는 callback

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 30);
CompletableFuture<Void> processed = future.thenAccept(result -> System.out.println("Result: " + result));

 


  - thenRun(Runnable) : 반환값을 받지 않고 다른 작업(동작)을 마찬가지로 반환 없이 처리만하는 callback

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 40);
CompletableFuture<Void> processed = future.thenRun(() -> System.out.println("Processing completed"));

 


  - callback 자체를 또 다른 스레드에서 실행할 수 있다.

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 50);
CompletableFuture<String> processed = future.thenApplyAsync(result -> "Result: " + result);

 

 

좋은 글

 

CompletableFuture 정리

CompletableFuture가 생긴 계기, 비동기 작업 메서드, 콜백 제공 함수에 대해 정리했습니다.

velog.io

 

 

 

Optional.ofNullable
Optional.of

 

 

 

Java의 Optional 클래스는 Java 8부터 도입된 클래스로, 값이 존재할 수도 있고 없을 수도 있는 값을 감싸는 컨테이너입니다. Optional 클래스는 명시적으로 값이 없음을 나타내는 데 사용되며, NullPointerException을 방지하고 코드를 더 명확하게 만드는 데 도움을 줍니다.

 

 

Optional.ofNullable

  : 주어진 값이 null이 아니면 해당 값을 감싼 Optional 객체를 반환하고, null이면 빈 Optional 객체를 반환합니다.

 

String str = "Hello";
Optional<String> optionalStr = Optional.ofNullable(str);
System.out.println(optionalStr.isPresent()); // true

String nullStr = null;
Optional<String> optionalNullStr = Optional.ofNullable(nullStr);
System.out.println(optionalNullStr.isPresent()); // false

 

 

 

 

Optional.of

 : 주어진 값이 null이 아닌 경우에만 해당 값을 감싼 Optional 객체를 반환합니다. 만약 주어진 값이 null이면 NullPointerException이 발생합니다.

 

String str = "Hello";
Optional<String> optionalStr = Optional.of(str);
System.out.println(optionalStr.isPresent()); // true

String nullStr = null;
Optional<String> optionalNullStr = Optional.of(nullStr); // NullPointerException 발생

 

 

정리

  • ofNullable: 값이 null일 수도 있는 상황에서 사용하며, null을 감싼 빈 Optional 객체를 반환합니다.
  • of: 값이 반드시 null이 아닌 경우에만 사용하며, null이 주어지면 NullPointerException이 발생합니다.

일반적으로 Optional.ofNullable을 사용하여 null을 처리하는 것이 안전하고, Optional.of는 값이 확실히 있음을 보장할 때 사용하는 것이 좋습니다.

 

 

 

그밖의 Optional

 

값 존재 여부 확인

  • isPresent(): Optional 객체가 값이 존재하는지 여부를 확인합니다.

 

값 가져오기

  • get(): Optional 객체에 있는 값을 가져옵니다. 값이 없는 경우 NoSuchElementException이 발생할 수 있으므로 isPresent()로 확인 후 사용하는 것이 좋습니다.

 

값이 없을 때 기본 값 설정

  • orElse(defaultValue): 값이 존재하면 해당 값을 반환하고, 값이 없으면 기본 값(defaultValue)을 반환합니다.

 

 

 

 

 

좋은 글

 

 

[JAVA] Optional 잘 사용하는 방법

Java 언어 설계자인 Brain Goetz는 Optional을 만든 의도를 아래와 같이 작성했다. API Note: Optional is primarily intended for use as a method return type where there is a clear need to represent "no result," and where using null is likel

kimtaesoo99.tistory.com

 

 

정리
Optionl에 null 할당 금지
Optional.get() 호출 전에 값을 가지고 있음을 확실하게 하라
 값이 없을 땐 orElse() , orElseGet() , orElseThrow() 처리
값이 없는 경우 아무 동작도 하지 않는다면 ifPresent() 활용
 isPresent() - get() 은 orElseXXX 등으로 대체
. 필드의 타입 및 생성자나 메소드 인자로 Optional 사용 금지
 단지 값을 얻는 목적이면 Optional 대신 null 비교
Optional 대신 빈 컬렉션 반환
Optional을 컬렉션의 원소로 사용 금지
of()와ofNullable() 혼동 금지
원시 타입의 Optional 은 OptionalInt , OptionalLong , OptionalDouble 사용
내부 값 비교는 Optional.equals 사용을 고려
 제약 사항이 있는 경우 filter 사용 고려

 

'코딩 > Spring' 카테고리의 다른 글

최근에 본 좋은 글들 (예외처리/일급컬렉션/API 디자인 - URI)  (1) 2024.12.02
JPA N+1 문제  (0) 2024.06.24
AOP, 프록시, Transactional  (0) 2024.06.20
MapStruct  (0) 2024.04.04
Spring Security Config 버전별 정보  (0) 2024.03.03