배움 __IL/TIL 2기

TIL : Extra-1(Optional, 동시성, stream, Assertions, IllegalStateException)

Mo_bi!e 2023. 8. 15. 22:52

I. Index

1. Optional 자료형

2. 동시성 문제

3. stream

4. Assertions (assertThat, ifPresent)

5. IllegalStateException

 

 

II. Contents

1. Optional 자료형

What (정의) : Nullable한 값을 감싸는 래퍼클래스이다. 명시적으로 값이 없는 경우와 다를 수있으며, NullPointerException을 방지할수있음

Why (존재이유) :

Null 안전성 향상 Null안전성 강화하기 위해서이다. NPS상황을 방지하고, 코드안전성을 향상시킴

가독성 향상 null체크와 관련된 복잡한 로직을 줄여줌

명시성 강화 값이 없을 경우에 대한 명시성을 코드에 반영이 가능함

 

//repository 에서...
@Override
public Optional<Member> findById(Long id) {

    //옵셔널로 감싸면 null인것을 방지할 수 있음
    return Optional.ofNullable(stroe.get(id));
}

 

How (방법) :

// 값을 갖는 Optional 생성
Optional<String> optionalValue = Optional.of("Hello");

// 값이 없는 Optional 생성
Optional<String> emptyOptional = Optional.empty();

// 값이 없는 경우에 대한 Optional 생성
Optional<String> optionalNullable = Optional.ofNullable(null);

// 값 가져오기 (값이 없으면 NoSuchElementException 발생)
String value = optionalValue.get();

// 값 가져오기 (값이 없으면 디폴트 값 사용)
String valueOrDefault = optionalValue.orElse("Default Value");

// 값 가져오기 (값이 없으면 Supplier를 통해 생성)
String valueOrGenerated = optionalValue.orElseGet(() -> generateValue());

// 값 가져오기 (값이 없으면 예외 던지기)
String valueOrThrow = optionalValue.orElseThrow(() -> new RuntimeException("Value not found"));

// 값 존재 여부 확인
boolean isPresent = optionalValue.isPresent();

// 값이 존재할 때 처리
optionalValue.ifPresent(val -> System.out.println("Value: " + val));

// 값 변환 및 처리 (매핑)
Optional<Integer> lengthOptional = optionalValue.map(String::length);
    public static void main(String[] args) {
        System.out.println("Hello world!");

        String a = "hi";
        String b = null;

        Optional<String> strOp = Optional.of(a);
        Optional<String> nulOp = Optional.ofNullable(b);

        System.out.println(strOp.get());
        System.out.println(nulOp.orElse("null 임 "));
        System.out.println(nulOp.isPresent());
//        strOp.orElseGet(() -> generateValue());


//        strOp.orElseThrow(() -> new ("not found"));

        strOp.ifPresent(val -> System.out.println("value"+val));


    }

e.g. (예) : 

마치 선물상자와 마찬가지이다. 선물상자안에 선물이 '무엇'이 들어있는지는 모르지만 '있는지 없는지'(상자를 흔들어서,상자의 무게로)는 미리 확인이 가능하다.

 

2. 동시성 문제 (가볍게)

What (정의) : 멀티스레드 환경에서 동시에 공유된 자원을 접근, 수정하는 과정에서 발생하는 문제 이로인한 데이터 일관성 문제 발생

 

Why (존재이유) : 스프링 어플리케이션은 싱글톤 빈을 사용하는 상황에서 여러 스레드가 동시에 실행될 수있는 환경에서 동작한다. 각 스레드가 공유 데이터 자원을 접근 수정할 수있기 때문이다.

 

How (방법) : 해결방법으로는

Synchronized 로 하나의 스레드만 실행시키기,

Locking Mechanism 스레드간 경합조건을 제어하고 데이터 일관성 유지함,

Thread-Safe 컬렉션 및 객체 사용 스프링이 제공하는 것으로서 스레드를 안전하게 사용할 수있는 컬렉션, 객체를 제공함

Spring의 Transactional 스프링의 트랜잭션 관리기능을 사용하여 DB작업등을 원자적으로 처리하고, 데이터 일관성 보장 함

 

 

e.g. (예) :

하나의 은행계좌에 여러명이 동시에 입출금 시도하는 상황으로 볼 수있음

 

3. stream (가볍게)

What (정의) : 자바8에서 제공되는 기능이다. 데이터의 '연속된 흐름'을 나타낸다. 결국 컬렉션, 배열같은 데이터 구조에서 이를 이용할 수있다.

 

Why (존재이유) : 

간결하고 가독성 있는 코드: 간결한 코드로 데이터 처리가 가능하다

병렬 처리의 용이성: 데이터를 병렬로 처리하는거이 간단해진다.

함수형 프로그래밍의 지원: 함수형 프로그래밍 개념 지원하기 때문에 불변성, 순수함수 활용이 가능하다

 

How (방법) :

3단계 (데이터소스 생성 -> 중개 연산 수행 -> 종단 연산 수행)

데이터 소스생성 : 다양한 데이터 소스로 부터 스트림을 생성한다

중개 연산 수행 : 스트림에 필터링, 매핑, 정렬을 수행한다.

종단 연산 수행: 마무리 후 결과 반환한다. 스트림을 닫으면 더이상 사용할수 없음

 

e.g. (비유) :

카페에서 커피를 주문할 때 메뉴, 사이즈, 원두종류 등을 선택하는것은 중개연산을 의미한다.

이를통해서 커피를 필터링하거나, 변형할수 있다.

그리고 주문이 완료되면 더이상 주문을 받을 수없다.

 

    public static void main(String[] args) {

        List<String> frus = Arrays.asList("사과", "바나나", "포도", "오렌지", "키위");

        List<String> 필터과일 = frus.stream()
                .filter(fru -> fru.length() >= 3)
                //람다식 방식으로 이렇게도 가능함
                //.map(fruit -> fruit.toUpperCase())
                //메소드 참조 방식 (String클래스에 정의된 정적 메소드임)
                .map(String::toUpperCase)
                //스트림을 이용해서 요소들의 컬렉션으로 수집하는 작업임
                //즉 스트림 -> 리스트
                .collect(Collectors.toList());

        //필터과일.forEach(fruit -> System.out.println(fruit)); //람다식 방식
        필터과일.forEach(System.out::println);
    }

이 외 알아두면 좋은 스트림 요소 처리 메소드

더보기
  1. map: 스트림의 각 요소를 변환하여 새로운 스트림을 생성합니다.
  2. filter: 주어진 조건에 맞는 요소만을 필터링하여 새로운 스트림을 생성합니다.
  3. collect: 스트림의 요소를 컬렉션으로 수집합니다 (예: 리스트, 세트, 맵 등).
  4. reduce: 스트림의 요소를 하나의 값으로 축소하는 작업을 수행합니다.
  5. sorted: 스트림의 요소를 정렬합니다.
  6. findFirst 및 findAny: 스트림에서 첫 번째 요소 또는 임의의 요소를 반환합니다.
  7. max 및 min: 스트림에서 최대값 또는 최소값을 찾아 반환합니다.

 

4. Assertions (assertThat, ifPresent)

What (정의) : 테스트코드에서 예상결과 실제결과를 비교하고 확인하는데 메소드 제공하는 유틸리티 클래스이다. 즉 값이나 조건이 예상과 실제가 일치하는지 보는것이다.

 

Why (존재이유) : 동작하지않는 코드를 발견하고, 수정하려면 테스트결과를 신뢰할 수있어야함 Assertions를 사용해서 확인함으로서 코드변경에 따른 영향을 추적할수있고, 예상대로 된다는것 확신가능함

How (방법) :

더보기
  1. assertEquals(expected, actual): 예상한 값과 실제 값이 같은지 확인합니다.
  2. assertTrue(condition): 주어진 조건이 true인지 확인합니다.
  3. assertFalse(condition): 주어진 조건이 false인지 확인합니다.
  4. assertNull(object): 주어진 객체가 null인지 확인합니다.
  5. assertNotNull(object): 주어진 객체가 null이 아닌지 확인합니다.
  6. assertSame(expected, actual): 두 객체가 같은 객체인지 확인합니다.
  7. assertNotSame(expected, actual): 두 객체가 다른 객체인지 확인합니다.

e.g. (예) :

 

 

5. IllegalStateException

    private void validateDuplicateMember(Member member) {
        memberRepository.findByName(member.getName())
                .ifPresent(m -> {
                    throw new IllegalStateException("이미 존재하는 회원입니다");
                });
    }

findByName은 optional로 선언되어있음

null이 아닌 'm'값이 있는 경우 (즉 Present true인 경우)  thorw를 던짐

 

여기서 IllegalStateException 는?

 부적절한 인수를 메소드 건내서 호출되는경우를 의미한다.