원티드 백엔드 챌린지 11월 1회차 정리

원티드 백엔드 챌린지 11월 1회차 정리

생성일
Nov 5, 2024 10:10 AM
최종 편집 일시
Last updated November 7, 2024
태그
JAVA

의미 있는 코드 Style

Constructor VS Static Factory Method

Java에서는 인스턴스 생성하는 방법은 대략 2가지 정도 된다.
첫 번째는 생정자를 이용하는 방법이고,
두 번째는 정적 팩토리 메서드를 사용하는 방법이다.

정적 팩토리 메서드의 장점

  1. 이름을 가질 수 있다. (메서드 이름 자체로 의미 전달이 된다.)
    1. 생성자에 넘기는 매개변수와 생성자 자체만으로는 반환될 객체의 특성을 제대로 설명하지 못한다. 반면 정적 팩토리는 이름만 잘 지으면 반환될 객체의 특성을 쉽게 묘사할 수 있다.
  1. 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다. (싱글턴, 메모리 효율)
    1. 불변 클래스는 인스턴스를 미리 만들어 놓거나 새로 생성한 인스턴스를 캐싱하여 재활용하는 식으로 불필요한 객체 생성을 피할 수 있다.
  1. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다. (다형성)
  1. 입력 매개변수에 따라 매번 다른 클래스의 인스턴스를 반환할 수 있다. (SOLID의 OCP)
  1. 정적 팩토리 메서드를 작성하는 시점에는 반환할 클래스가 실제로 존재하지 않아도 된다. (예를 들어 인터페이스를 반환한다면 실제 구현체가 없어도 선언에 문제가 없다.)

정적 팩토리 메서드의 단점

  1. 상속할 수 없다.
    1. 기본 생성자의 접근 제한자가 private으로 선언되기 때문에 상속할 수 없다.
  1. 정적 팩토리 메서드 찾기가 어렵다.
    1. 일반적인 생성자와 다른 메서드명을 사용하기 때문에, 이러한 코드가 익숙하지 않은 동료 개발자는 인스턴스를 생성하는 역할을 하는 메서드 찾기가 쉽지 않을 것이다.
    2. 따라서 일반적으로 사용하는 형태를 알아두면 좋다. 아래는 예시다. from: 매개변수 하나 받아서 해당 타입의 인스턴스를 반환하는 형변환 메서드 Date d = Date.from(instant); of: 여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 집계 메서드 Set<Developer> dev = EnumSet.of(a, b, c); valueOf: Boolean isTrue = Boolean.valueOf("true"); 이런 느낌.

Builder 패턴

생성자와 정적 팩토리의 한계

선택적 매개변수가 많을 때 정적 팩토리와 생성자는 적절히 대응하기 어렵다.
Why?
  1. 메서드를 호출하는 과정에서 파라미터를 할당할 때 매개변수의 순서를 틀리거나 누락할 수 있다는 휴먼 에러를 내포하고 있다.
  1. 가독성이 매우 현저하게 떨어진다.
How?
  1. Builder패턴을 클래스 내부에서 직접 구현하기
  1. Lombok에서 제공하는 어노테이션으로 적용하는 방식
 

불변 객체

불변식(Invariant)

프로그램이 실행되는 동안 또는 정해진 기간 동안 반드시 만족해야 하는 조건을 말한다. 다시 말해 변경을 허용할 수 있으나, 주어진 조건 내에서만 허용한다는 뜻이다.
예를 들면, “리스트의 경우 size의 크기는 반드시 0이상이어야 하고 한 순간이라도 음수 값이 될 수 없다.”라는 조건식이 List.size()의 불변식이다.

불변 클래스 선언하는 법

  1. final 클래스
  1. 클래스의 모든 필드를 final로 선언 한다. 단, 예외도 존재한다.
  1. private 필드
  1. 클래스의 확장(extends)을 막는다: only private, Static Factory (상속을 하는 순간, 설계자의 의도를 망가트린다.)

불변 객체의 특징

  1. 불변 객체는 단순하다. (예상대로 동작할 것이므로)
  1. 불변 객체는 자유롭게 공유할 수 있고 동일한 불변 객체 간의 내부 데이터를 공유할 수 있다.
  1. 불변 객체는 그 자체로 실패 원자성을 제공한다. (원자성: 성공하면 새로운 값 반환, 실패하면 오류 반환)

람다와 스트림

동작 파라미터화

동작(Method)를 Method의 파라미터로 전달하는 방식을 말한다.

람다

Java8 부터 추가된 기능으로, 익명 함수를 말한다.
(int arg1, String arg2) -> {System.out.println("Two arguments" + args1 + "and " + arg2;}

람다가 왜 중요할까?

  1. Java 8부터 함수를 값으로 취급할 수 있다. (1급 객체)
  1. 가독성이 좋아진다.

어떻게 사용하는 게 좋을까?

  1. 메서드를 함수처럼 선언할 수 있고 변수에 할당할 수 있다.
  1. 함수형 인터페이스라는 문맥에서 람다 표현식을 사용할 수 있다.

유효한 람다 표현

람다 표현식의 문법은 굉장히 유연하다.
(String s) -> s.length(); (String s) -> String::length; (Apple a) -> a.getWeight() > 25; (Apple a, Apple b) -> a.getWeight().compare(b.getWeight());

람다식 메서드 참조

실행하려는 메서드를 참조해서 매개 변수와 리턴 타입을 알아내어, 람다식에서 불필요한 선언부를 생략할 수 있는 문법을 말한다.
.map( (String s) -> s.length();) .map(String::length); (Apple a, Apple b) -> a.getWeight().compare(b.getWeight()); (a, b) -> a.getWeight().compare(b.getWeight()); .comparing(Apple::getValue) .comparing(apple -> apple.getWeight().getValue()) .comparing(Apple::getValue);

스트림

데이터 처리 연산을 지원하도록 Source Data에서 추출된 연속된 요소
notion image

스트림의 특징

  1. 선언형 코드를 작성할 수 있다. (여러 변화하는 요구사항에 대응하기가 좋다.)
  1. 여러 중간 연산을 연결해서 복잡한 데이터 처리 파이프라인을 만들 수 있다. (메서드 체이닝)
  1. 외부 반복이 아닌 내부 반복자를 사용한다.
    1. notion image
  1. 스트림 메서드
    1. index.stream().sorted((o1, o2) -> o1.compareTo(o2)); index.sort((o1, o2) -> o2.compareTo(o2)); index.sort(Integer::compareTo);

null로 인해 발생하는 문제

  1. 에러의 근원
  1. 아무런 의미가 없다.
  1. null 처리를 위한 if-else문으로 가독성이 떨어진다. (null 검증 코드는 가독성을 떨어뜨린다.)
  1. 자바 철학에 위배가 된다. (null만 포인터 개념을 가진다.)
  1. 형식 시스템에 구멍이 생긴다.

올바른 null 처리 방법

Type 시스템을 이용해서 값이 없는 경우, null이 아닌 빈 값(Empty)을 갖도록 하고 값이 있는 경우, 주어진 형식에 맞는 값을 갖도록 하는 방식이 좋다.

Optional<T>

Optional<T>는 T타입의 값을 캡슐화하는 클래스이다. 값이 존재하는 경우, 그 값을 감싸지만, 값이 존재하지 않는 경우, null이 아닌 Optional.Empty 값으로 감싼다.

Optional 사용법

  1. Empty 값으로 Optional 생성
  1. Optional.of()
  1. Optional.ofNullable()
 

Optional 유용한 Method

  1. isPresent()
    1. Optional 값이 존재하는 경우, true, 아니면 false를 리턴한다.
    2. 공식문서상으로는 성능상 문제가 있다고 한다.
  1. T get();
    1. 값이 존재하면 값을 반환하고, 그렇지 않다면 NoSuchElementException을 던진다.
  1. orElse(T other);
    1. Optional이 값을 포함하지 않고 있을 때 Default 값을 제공할 수 있다.
  1. orElseGet()
    1. Optional이 값을

Auto Boxing/Unboxing의 문제

개발자의 편의성과 가독성에는 도움이 되지만, 성능 문제를 일으키는 숨은 요인 중 하나다.
Collection 프레임워크를 사용하는 것보다 stream을 사용하는 것이 성능 상 이득이다.