자바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 등 데이터 오브젝트를 설계할 때 많은 도움을 얻을 수 있다.


1. NPE

1-1. NPE는 null로 인하여 발생하는 Runtime Exception이다.

1-2. null 유발에 대한 고찰

개발하다 보면 객체의 null에 대한 가능성을 고려해야 하는 경우가 생긴다.

예제 코드로 이러한 경우를 확인하고 해결 방법을 생각해 보자.

2. 실습

null의 발생 경우는 매우 광범위 하고 전부를 다룰 수 없기 때문에 이번 실습은 String 위주로 진행한다.

2-1. NPE 유발

  • 배열 이나 오브젝트 등에서 null의 가능성을 배제한 함수 호출을 한다.
  • null에는 toString()이라는 함수가 존재하지 않으며 NPE를 유발한다.
//Case.1
String[] arrStr = new String[2];
arrStr[0] = "arr1";
arrStr[1].toString(); //null.toString();

//Case.2
Map<String, String> map = new HashMap<String, String>();
map.put("id", "admin");
map.put("pwd", null);
map.get("pwd"); //null.toString();
map.get("name"); //null.toString();

//Case.3
public Object getObj(){
	Object obj = null;
	return obj;
}
Object obj = getObj();
obj.toString(); //null.toString();

2-2. NPE 예방

  • null 가능성을 배제할 수 있는 구조를 사용.
//obj에 null의 가능성이 존재
//Case.1 : null.equals() NPE 유발 가능성 발생
if(obj.toString().equals("str")){
	return false;
}
//Case.2 : "str"은 문자열로 equals() 함수 사용이 가능
//obj.toString()에 NPE가능성이 존재하지만 equals()의 NPE 배제의 예제
if("str".equals(obj.toString())){
	return true;
}
  • null을 피할 수 있는 함수의 활용.
obj.String(); //null.toString();
//null처리된 String객체의 함수 활용하여 위 Case.2의 문제를 해결
if("str".equals(String.valueOf(obj))){
	return true;
}
  • try-catch의 활용

Exception(예외)는 에러가 아니다. NPE의 발생을 로그나 메시지처리로 핸들링해 보자.

try{
	obj.toString();
} catch(NullPointerException npe){
	"NPE예외를 핸들링 해보자"
}

3.결론

3-1. String외에도 배열, File 등 객체를 생성할 때 모종의 이유로 null인 상태에서 함수 사용 등 참조하면 NPE를 발생시킬 수 있다.

3-2. NPE의 예방은 null을 피하기 위한 노력, 코딩 습관이라고도 할 수 있으니 예제 외에도 NPE를 피할 방법을 계속해서 고민하자.

Map

Map은 key-value 방식을 사용하여 대응관계를 쉽게 표현 할 수 있는 자료형이다.

Map은 리스트나 배열처럼 순차적으로(sequential) 요솟값을 구하지 않고 키(key)를 이용해 값(value)을 얻는다.

Map은 배열처럼 순차적인 데이터 처리를 하지 않고 순서를 유지하지 않는다

DB의 pk같이 key는 중복을 허용하지 않지만 value는 중복이 가능하다.


1. 개요

1-1. HashMap으로 생성한 Map의 모든 값을 출력.

1-2. 여러가지 함수를 사용하여 실습.

  • entrySet()
  • keySet(), get()
  • values()
  • forEach() ※Java 8버전 이상 사용가능

2. 실습

2-1. 비즈니스 처리에 사용될 Map

Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "val1");
map.put(2, "val2");	
map.put(3, "val3");

2-2. entrySet()

entrySet() 함수로 Entry를 리턴 받아 getkey(), getValue() 함수를 사용한다.

for (Entry<Integer, String> entrySet : map.entrySet()) {	
	System.out.println("key="entrySet.getKey() + " :: value=" + entrySet.getValue());	
}

// result
// key=1 :: value=val1
// key=2 :: value=val2
// key=3 :: value=val3

2-3. keySet(), get()

keySet() 함수로 모든 키를 Set으로 리턴받아 Map에서 get()으로 찾는다.

for (Integer key : map.keySet()) {	
	System.out.println("key="key + " :: value=" + map.get(key));	
}

// result
// key=1 :: value=val1
// key=2 :: value=val2
// key=3 :: value=val3

2-4. values()

value만 필요한 경우 values() 함수로 Collection을 리턴 받는다.

Collection<String> values = map.values();
System.out.println(values);

// result
// [val1,val2,val3]

2-5. forEach()

map을 순차 탐색하여 key, value를 받는다. 람다 활용

map.forEach((key, value) -> {	
	System.out.println("key="key + " :: value=" + map.get(key));	
});

// result
// key=1 :: value=val1
// key=2 :: value=val2
// key=3 :: value=val3

 

3. 결론

정형화된 class의 매개변수나 리턴값은 내용을 유추할 수 있으나 Map은 그렇지 못한 경우가 있다.

이럴 때 Map의 전체 데이터를 출력해 보자

자바 Stream API는 배열 또는 컬렉션 인스턴스에 함수를 조합하여 필터링, 가공 등을 통하여 결과를 얻을 수 있다.

또한 람다를 사용하여 가독성 증가 및 간결하게 표현 가능하다. for 또는 foreach가 아닌 함수형 처리가 가능하다.


1. 개요

1-1. 자바 8 이후 Stream API를 통한 배열처리가 가능하다.

1-2. 실습과 예제 코드로 배열의 처리 방법을 비교해보자.

 

2. 요구사항

2-1. 사용자별 등급(Grade), 비용(Cost) 존재

2-2. 사용자 배열을 등급에 따라 비용에 할인을 적용

 

3. 실습

3-1. 비즈니스 처리에 사용될 클래스

@Getter
@Setter
public class Member {
    private Long id;
    private String name;
    private Grade grade;
    private int cost;

    public Member(Long id, String name, Grade grade, int cost) {
        this.id = id;
        this.name = name;
        this.grade = grade;
        this.cost = cost;
    }
}
public enum Grade {
    BASIC
    , VIP
}
List<Member> memberList = new ArrayList<>();
memberList.add(new Member(1L,"memberBASIC", Grade.BASIC, 15000));
memberList.add(new Member(2L,"memberVIP", Grade.VIP, 15000));

3-2. for을 사용

        for (int i = 0; i < memberList.size(); i++) {
            Member member = memberList.get(i);
            if(Grade.VIP.equals(member.getGrade())){
                member.setCost((int) (member.getCost()*0.5));
                memberList.set(i,member);
            }
        }

3-3. stream을 사용

  • 사용한 함수보다 더 많은 stream 함수가 있으니 API 문서를 참고하여 활용해 보자.
        memberList.stream()
                .filter(m->Grade.VIP.equals(m.getGrade()))
                .forEach(m->m.setCost((int) (m.getCost()*0.5)));

 

4. 결론

4-1. for의 강점

  • for문은 단순 인덱스 기반
  • stream보다 빠르고 오버헤드 발생이 없다

4-2. stream의 강점

  • stream의 제공 함수들의 활용으로 가독성이 좋아진다.
  • 함수형 프로그램으로 전환이 용이하다.
  • 코딩 스타일의 일관성을 가질수 있다.

4-3. 생각

개발하다 보면 뭐가 정답이라는게 모호한 경우가 많다.이럴 때 가장 보편적인 선택 방법은 장점이 단점보다 강세일 때라고 생각한다.

그냥 사용하고 마는 것이 아닌 각 클래스 및 함수를 타고 들어가 기능과 정의를 확인하고 상황에 맞는 개발을 할 수 있도록 노력하자.

1. 개요

1-1. 자바의 많은 버전 중 무료, 가장 많이 사용되는 버전

  • 23년 9월 Java SE 21버전까지 출시 되었지만 가장 많이 사용하는 버전으로 8버전을 꼽는다.
  • 자바 공화국으로 불리는 대한민국 실무에서 실제 8버전 환경에서의 개발을 많이 접한다. 

1-2. LTS(Long Term Support) 버전

  • 오랜 기간 버그 픽스 등 패치를 지원하는 버전을 말한다.
  • 때문에 해당 버전으로 개발 후 오랜기간 자바 버전 패치 없이 지원이 가능하다.

 

2. JAVA 8 의 핵심 기능 및 특징

2-1. 8버전 자바에는 다음과 같은 핵심 기술과 특징이 포함된다.

  • 하기 내용은 자바 8버전의 핵심 기술로 예제와 함께 개별 단위로 익히도록 하자.
  1. Lambda expression(람다 표현식)
  2. Functional interface(함수형 인터페이스)
  3. Default method(디폴트 메서드)
  4. Stream(스트림)
  5. Optional(옵셔널)
  6. 새롭게 추가된 날짜 및 시간 API
  7. CompletableFuture(컴플리터블 퓨처)
  8. JVM의 변화
  9. Base64 Encode/ Decode를 위한 표준 API

 

3. 마치며

  • Oracle에서 제공하는 Java(Jdk) 8버전은 202 마이너 버전까지가 무상이다.
  • 오라클 자바 다운로드 링크 및 설치 가이드를 참고하여 자바를 설치해보자.

Java Archive Downloads - Java SE 8 (oracle.com)

 

Java Archive Downloads - Java SE 8

We’re sorry. We could not find a match for your search. We suggest you try the following to help find what you’re looking for: Check the spelling of your keyword search. Use synonyms for the keyword you typed, for example, try "application" instead of

www.oracle.com

2023.09.26 - [IT] - 윈도우 자바(java)설치 및 환경 변수 설정 가이드

 

윈도우 자바(java)설치 및 환경 변수 설정 가이드

개발 혹은 서버 환경 구축을 위한 자바설치 가이드 오라클 무료버전 자바 설치 (1.8.202) 1. 자바 설치 가이드 https://www.oracle.com/kr/java/technologies/javase/javase8-archive-downloads.html 오라클 1.8.202버전 jdk를

yangjaya.tistory.com

 

  • 개발 혹은 서버 환경 구축을 위한 자바설치 가이드
  • 오라클 무료버전 자바 설치 (1.8.202)

1. 자바 설치 가이드

자바설치 1-1
자바설치 1-2
자바설치 1-3
자바설치 1-4
자바설치 1-5

  • 설치가 완료되면 설치 경로에서 확인

자바설치 1-6

 

2. 자바 환경 변수 설정

  • 윈도우에서 시스템 환경 변수 편집 실행

자바 환경 변수 2-1
자바 환경 변수 2-2

  • 새로만들기 > 변수 이름, 값 입력 > 확인
  • 변수 값은 설치한 jdk의 경로로 지정한다 (C:\Program Files\Java\jdk1.8.0_202)
  •  

자바 환경 변수 2-3

  • 새로만들기 > 변수 이름, 값 입력 > 확인
  • 변수 값은 jdk의 lib 경로로 지정한다 (%JAVA_HOME%\lib)

자바 환경 변수 2-4

  • Path변수에 JAVA_HOME경로를 추가한다

자바 환경 변수 2-5

  • 새로 만들기 > 자바의 bin경로 입력 > 위로 이동(최상단으로 이동) > 확인

자바 환경 변수 2-6

  • CMD를 열어서 설치된 자바를 확인한다
  • 윈도우+R > CMD > java -version 입력 > 설치된 자바 확인

자바 환경 변수 2-7

 

'IT' 카테고리의 다른 글

윈도우 톰캣(tomcat) 설치 가이드  (0) 2023.09.26

+ Recent posts