자바8의 핵심기능 중 하나인 Optional 클래스에 대하여 알아보자

기존에 NPE에 대한 소개를 했었는데 Optional을 사용하여 복잡한 조건 없이 오브젝트에 대한 null을 관리 할 수 있다.

Optional<T> 클래스는 Integer나 Double 클래스처럼 'T'타입의 객체를 포장해 주는 래퍼 클래스(Wrapper class)기 때문이다.

따라서 Optional 인스턴스는 모든 타입의 참조 변수를 저장할 수 있으며 null을 관리 할 수 있다.


1. Optional

1-1. Optional 클래스에 진입하면 static에 EMPTY로 빈 객체를 생성, 공유 하고있다.

1-2. T로 클래스를 래핑하여 빈 값에 대한 처리와 리턴을 하고 있다.

 

2. 활용

2-1. Optional의 간단한 예제를 진행한다. 더 많은 함수 활용은 DOCS를 참고하자.

private void test(){
	//ofNullable()함수로 NPE 가능성이 있는 함수를 생성하여 Optional에 담는다.
    Optional<String> optional = Optional.ofNullable(get값이있을수도없을수도());
    //값이 없다면 orElse로 일종의 null 처리가 가능하다.
    String id = optional.orElse("tempId");
  }

2-2. Spring에서 많이 사용하는 JPA의 경우를 예로 들어보자.

private void test2(){
	//Entity객체를 JPA쿼리하면 리턴이 Entity가 아니라 Optional이다.
    Optional<Entity> optional = EntityRepository.findById(1L);
    //isPresent()함수로 null 여부를 확인한다. 쿼리 결과가 없기때문에 return;
    if(!optional.isPresent()){
      return;
    }
    //있다면 Entity로 반환한다.
    Entity ent = optional.get();
    ...
    ...
    ...
  }

3. 한계

3-1. null을 별도의 클래스에 맡기다니 너무 편리하고 파격적으로 느껴질 수 있지만. Optional에도 한계는 존재한다. 실제 위의 샘플 코드는 실무에서 저런식으로 작성되지 않으며 클린하지 못한 코드이다.

3-2. Optional은 NPE발생 가능에 따라 리턴이 없음을 명확히 하기위헤 메소드의 반환 타입으로 사용되도록 매우 제한적이다. 첨부한 oracle-optional링크를 꼭 읽어보기 바란다.

3-3. 한계의 예

  • NPE는 회피 가능하지만 실제 값에 대한 보증은 하지 않기 때문에 NoSuchElementException 가능성
  • T를 포장한 래퍼 클래스기 때문에 메모리할당이 필요하고 Optional에서 한번더 접근해야하기 때문에 접근 비용이 발생한다.
  • isPresent()같은 함수의 무분별한 사용을 하게되면 코드 가독성을 떨어트린다.

 

4. 결론

좋아 보이는 기능도 대충 구글링을 통해 함수나 찾아보고 무분별한 사용하기 이전에 DOCS를 참고하여 해당 클래스의 의도와 정확한 사용을 이해한 후에 반영해야. 좋은 기능을 100퍼센트 활용 할 수 있을것이다.여러 뎁스의 if(null !=)에 대한 편의 제공이 되었을때 우리는 어떻게 사용할 것인가.


https://www.oracle.com/technical-resources/articles/java/java8-optional.html

 

Tired of Null Pointer Exceptions? Consider Using Java SE 8's Optional!

Make your code more readable and protect it against null pointer exceptions. A wise man once said you are not a real Java programmer until you've dealt with a null pointer exception. Joking aside, the null reference is the source of many problems because i

www.oracle.com

https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html

 

Optional (Java Platform SE 8 )

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value. Additional methods that depend on the presence or absence of a contained value are provided, such as orEl

docs.oracle.com

https://yangjaya.tistory.com/entry/Java-NPENullPointerException%EC%97%90-%EB%8C%80%ED%95%98%EC%97%ACString-NPE

 

[Java] NPE(NullPointerException)에 대하여(String NPE)

1. NPE 1-1. NPE는 null로 인하여 발생하는 Runtime Exception이다. 1-2. null 유발에 대한 고찰 개발하다 보면 객체의 null에 대한 가능성을 고려해야 하는 경우가 생긴다. 예제 코드로 이러한 경우를 확인하

yangjaya.tistory.com

 

IE EOS 이슈와 함께 ActiveX의 사용도 당연히 못하게된 상황에서

기존에 브라우저에서 클라이언트의 exe를 호출하던 기능을 못 사용하게 되었다.

서버에서 클라이언트 PC의 제어는 당연히 불가능 했기 때문에 해결방법을 찾아야 했다.


1. 양자의 사고

1-1. 서버는 클라이언트PC를 제어를 하지 못한다.

1-2. 클라이언트 개발자로부터 웹 소켓을 사용한 SSO 연동 테스트 모듈을 제공할 때 node.js를 사용했다는 점

1-3. npm을 사용해 보면서 Node.js가 다양한 일을 할 수 있구나 정도의 생각을 가지고 있었음

1-4. 스크립트는 애초에 클라이언트 사이드 언어인데 Node.js가 exe 제어를 할 수 있다면 활용할 수 있지 않을까?

1-5. 실제 Node.js에는 exe를 실행 시켜줄 수 있는 기능이 존재하였다.

2. 설계

2-1. 1차, 호출에 대한 구조

2-2. 2차, 실제 모듈 구조

3. 동작

3-1. 클라이언트가 설치, 실행과 동시에 node.js로 로컬서버를 open한다.

3-2. 웹 스크립트에서 이벤트가 발생하면 로컬서버를 호출한다.

3-3. 로컬서버가 실행시켜줘.exe를 실행한다.

4. node.js의 활용

4-1. npm child_process

//자바로 치면 라이브러리 import
const { spawn } = require('child_process');
//실행함수(실행할 exe, args)
spawn('note.exe', ['first arg']);

5. 결론

본문 예제에서의 실행시켜줘.exe의 스팩은 알지 못하며 클라이언트의 영역이였기 때문에 메모장으로 간단한 예제 구현 까지 진행하였다.

나는 클라이언트 제어를 위해 Node.js를 활용하였는데 Node.js가 "확장성 있는 네트워크 애플리케이션과 서버 사이드 개발에 사용되는 소프트웨어 플랫폼" 이라는 위키를 보고 거꾸로 사용한건 아닌지 고민하며

node.js 고수의 답변을 기다려 본다.


https://www.npmjs.com/package/child_process

 

child_process

This package name is not currently in use, but was formerly occupied by another package. To avoid malicious use, npm is hanging on to the package name, but loosely, and we'll probably give it to you if you want it.. Latest version: 1.0.2, last published: 8

www.npmjs.com

 

간단하게 표현하자면 멀티 스레드 환경에서 long을 리턴하는 API를 개발해야하는 경우가 있었다.

AtomicLong은 Java의 Number클래스를 상속하고 있으며 long을 리턴하게 된다.

멀티 스레드 환경 메모리 참조를 하게 될경우 synchronized없이 Thread-safe한 활용을 확인해보자.


1. 멀티 스레드

그림과 같이 멀티 스레드 환경에서 공통의 API를 호출 하고 서버는 메모리 참조하여 long을 리턴해야하 하는 케이스가 발생 하였다.

//메모리에 long을 선언한다.
public static long rtn = 0L;
//API는 메모리 long을 +1 하여 리턴한다.
public long API(){
	return rtn++;
}

이때 해당 함수와 같이 일반 long을 활용하여 리턴할 경우 같은 메모리 주소를 참조하여 1,2,3,4 리턴이 아닌 1,2,2,3 같이 동시성 문제를 야기 할 수 있다.

2. Atomic

이때 Java의 Atomic 클래스는 synchronized보다 적은 비용으로 동시성을 보장한다.

3. 실습

이번 실습은 Atomic 클래스 중 AtomicLong을 활용한다.

3-1. AtomicLong 생성 및 기본 값 세팅

//생성
AtomicLong aLong = new AtomicLong();
//값 세팅
aLong.set(1);
//값 가져오기
aLong.get();
//생성과 동시에 값 세팅
AtomicLong aLong2 = new AtomicLong(10);

3-2. 기본적인 더하기 빼기 및 리턴 함수 활용

  • getAndIncrement() : 리턴 후 1증가
  • incrementAndGet() : 1증가 후 리턴
  • getAndDecrement() : 리턴 후 1감소
  • decrementAndGet() : 1감소 후 리턴
AtomicLong aLong = new AtomicLong(1);
aLong.getAndIncrement();//rtn : 1, aLong : 2
aLong.incrementAndGet();//rtn : 3, aLong : 3
aLong.getAndDecrement();//rtn : 3, aLong : 2
aLong.decrementAndGet();//rtn : 1, aLong : 1

4. 결론

보통 API나 비즈니스 처리를 개발하다 보면 DB를 쿼리해서 유일 값을 리턴한다던가 메모리 참조한 리턴을 활용하는 경우가 많지는 않았다.

이럴 때 Atomic 클래스를 활용하면 자바의 고유 기능으로 별도의 처리 없이 효과적인 스레드 작업이 가능하다.


https://learn.microsoft.com/ko-kr/dotnet/api/java.util.concurrent.atomic.atomiclong?view=xamarin-android-sdk-13

 

AtomicLong 클래스 (Java.Util.Concurrent.Atomic)

long 원자성으로 업데이트할 수 있는 값입니다.

learn.microsoft.com

 

 

 

Java 8은 날짜 및 시간 작업을 처리하기 위한 강력하고 유연한 API를 포함하는 패키지를 도입했습니다.

기존의 날짜 관련 클래스의 단점을 많이 보완 가능한 유용한 API입니다.

이 포스팅에서는 "LocalDateTime" 위주의 실습과, API에 대해 자세히 알아보고, 기능을 살펴봅니다.

"java.time"  "LocalDate" "LocalTime" "LocalDateTime"


1. LocalDateTime

LocalDateTime은 `java.time`패키지의 일부로 표준 시간대가 없는 날짜, 시간을 표현 할 수 있다.

2. 실습

2-1. LocalDateTime 생성 및 값 가져오기

//현재 날짜와 시간을 나타내는 개체
LocalDateTime currentDateTime = LocalDateTime.now();
//특정날짜(현재 블로그 작성 시간)로 만드는 개체
LocalDateTime specificDateTime = LocalDateTime.of(2023, 11, 26, 14, 30);
//직관적인 함수명으로 쉽게 값들을 얻어올 수 있다.
int year = date.getYear(); // 년도
Month month = date.getMonth(); // 월
int day = date.getDayOfMonth(); // 일

2-2. LocalDateTime의 시간 변경

//현재+7일+3시간
LocalDateTime futureDateTime = currentDateTime.plusDays(7).plusHours(3);
//현재-3개월-15분
LocalDateTime pastDateTime = currentDateTime.minusMonths(3).minusMinutes(15);

2-3. LocalDateTime의 포맷 변경 및 데이터 파싱

//yyyy-MM-dd HH:mm:ss형식의 포맷을 생성한다.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//현재 시간을 포매팅한 문자열을 생성한다.
String formattedDateTime = currentDateTime.format(formatter);
//특정 날짜 문자열을 포매터를 사용하여 LocalDateTime으로 파싱한다.
LocalDateTime parsedDateTime = LocalDateTime.parse("2023-11-26 14:30:00", formatter);

3. 결론

개발자라면 유창한 영어 실력이 아니더라도 알 수 있을 정도의 쉬운 함수들로 실습을 해보았다.

이처럼 Java 8버전 이상의 패키지에서 날짜 및 시간 구성 요소를 다루기 쉽게 복잡도를 낮추었다.

'java.time'패키지를 조금만 이해한다면 유연하고 간단한 날짜 처리 및 VO, Entity 등 데이터 오브젝트를 설계할 때 많은 도움을 얻을 수 있다.

+ Recent posts