studybook
  • Introduction
  • 실무 하며 깨닫는 부분 정리
    • 옵션에 대해서
    • 코드 작성의 순서
    • 자바 프로그램에 문제가 생겼다면
    • 장애 대처법
  • Logstash, Beats 정리
  • Zookeeper 정리
  • Message Queue 정리
    • RabbitMQ 삽질
  • Java 관련 정리
    • Java Primitive Wrapper class
    • Java NIO
    • Java8 Double colon operator
    • Effective Java
      • 4장
      • 5장
      • 6장 - Enum, Annotation
      • 7장 - Method
      • 8장 - 프로그래밍 일반
      • 9장 - Exception
    • Java8 Lambda expression
    • JDBC
    • Linux에서 WatchService 이상동작
  • Spring 관련 정리
    • Spring Bean init, destroy 순서
    • Spring Async Controller
    • Spring Executable jar 웹 개발 및 배포
    • Spring Boot Font 배포 에러
    • Spring AOP
      • Spring AOP로 모든 Request 로그 남기기
    • Spring Cache
    • Spring Cloud
      • Consul로 spring 설정 관리하기
    • Spring Test
      • Spring Test DirtiesContext
      • Spring Test MockBean, SpyBean
      • Spring Test Dynamic @Scheduled
    • Spring JDBC
    • Spring Validation
    • Spring Transaction Management
      • Spring with JTA 삽질
    • Spring에서 효율적으로 Static resource 관리하기
    • Zuul을 사용해서 Spring Reverse proxy 만들기
    • Spring Security
    • 스프링 어노테이션이 안 먹힐 때 의심해볼만한 것
    • Spring Data
    • Spring Webflux
      • Tobi 강연
  • 코드 리팩토링
    • 한번에 하나씩
  • 지속적 통합 (CI)
    • Jenkins pipeline 삽질기
  • Log Aggregator 정리
    • Flume 테스트
    • Fluentd 테스트
  • Web Socket 정리
  • Akka
    • Actor 모델
    • Supervision
  • IE 8 대응 정리
  • 함수형 프로그래밍
    • 모나드
  • Netty
    • Netty 기본 예제
    • Netty 주요 특징
    • Netty 부트스트랩
    • Netty 채널 파이프라인, 코덱
    • Netty 이벤트 모델
    • Netty 바이트 버퍼
  • 스칼라 관련 정리
    • Maven으로 컴파일하기
    • Scala def 괄호 여부의 차이
    • 스칼라 function, method 차이점
    • ScalaTest와 Spring 연동하기
    • Programming in Scala
  • J2S 컨퍼런스
  • Android
    • 테스트
    • NDK
  • DDOS
  • HTTP
  • HttpClient
  • Container
    • Image 개요
    • cri-o
    • kata containers
    • Open Container Initiative Image
    • Buildkit
  • Github pages
  • Static Website
  • Webhook
  • Service Discovery Tools
    • Etcd
    • Eureka
    • Consul
      • ACL
    • 비교
  • React
    • JSX
    • React Element
    • Components, Props
    • State, Lifecycle
    • Handling Event
    • Flux
  • Vagrant
    • SSH 접속
  • Linux
    • Systemd
    • Alternatives
  • Messaging protocols
    • XMPP
    • AMQP
  • Windows
    • Windows10 내장 우분투에 ssh 클라이언트로 접속하기
    • Windows10 Hyper-V와 Virtual Box가 충돌을 일으켰을 때
    • Hyper-V 기반 docker에서 Shared Drives 설정 실패할 때
    • 윈도우 개발환경 설정
    • Docker desktop 없이 docker 환경 세팅하기
    • UWP 앱을 항상 관리자권한으로 실행하는 바로가기 만들기
  • Spring camp 2017
    • Project Reactive
    • 이벤트 소싱
    • CQRS
  • Spring webflux
  • 리액티브 프로그래밍
  • Linux Settings
    • 홈서버 백업 및 복구기
    • 홈서버 트러블슈팅
  • Kubernetes
    • k3s 설치 및 삽질
    • pod resources
    • Argo workflow
    • 트러블 슈팅
      • Kubernetes namespace의 phase가 Terminating에서 멈춰있을 때
    • 쿠버네티스 마스터
    • Knative
    • Knative Pipeline
    • Aggrerated API server
    • Accessing the API
      • Authenticating
  • Sonarqube
  • HTTP/2
  • Go
    • Go Module
    • Go dependency injection
    • Go Error handling
    • Go in Action
      • 3장 패키지
      • 4장 배열, 슬라이스, 맵
      • 5장 GO의 타입 시스템
      • 6장 동시성
      • 7장 동시성 패턴
      • 8장 표준 라이브러리
      • 9장 테스트와 벤치마킹
    • Go Channel 사용법
  • Cloud Native
Powered by GitBook
On this page
  • Raw type을 쓰지 않기
  • 컴파일 경고 메세지 줄이기
  • 배열보다 List 쓰기
  • 공변, 불변
  • 바운드 와일드카드
  • PECS
  • 반환 타입에는 와일드카드 사용하지 않기
  • Heterogeneous Container
  1. Java 관련 정리
  2. Effective Java

5장

Raw type을 쓰지 않기

Raw type은 제네릭 타입에서 매개변수 없이 사용하는 타입을 의미한다. 말하자면 List 처럼 뒤에 <> 없이 사용되는 경우라고 말할 수 있다. 간혹 모든 종류의 List를 다 사용할 수 있는 메소드를 만들기 위해서 Raw type을 사용하는 경우가 있는데, 그렇게 해서는 안 된다.

그 이유는 다음과 같다.

  1. 잘못 사용하고 있어도 컴파일러가 컴파일 에러를 뱉지 않는다.

  2. 타입의 안정성을 상실하게 된다.

그 대안으로 Unbounded wildcard type을 사용하자. 이는 List<?> 처럼 패러미터에 ?가 들어간 것이다. 이 경우에 어떤 리스트든 받을 수 있지만 리스트의 타입 불변성이 보장된다.

다만 Raw type을 쓸 수 밖에 없는 상황이 두 가지 있다. 하나는 List.class처럼 클래스 리터러시를 쓸 때이고 나머지 하나는 myObj instanceof List 처럼 instanceof 연산자를 쓸 때이다. 그 이유는 런타임에선 제너릭 타입의 패러미터 정보가 없어지는 까닭이다. 대신에 instanceof 연산자를 쓰게 되면 Unbounded wildcard type으로 캐스팅하도록 해야한다.

컴파일 경고 메세지 줄이기

당연한 소리지만 컴파일 경고 메세지는 없앨 수 있는 만큼 없애야된다. 하지만 부득이하게 줄일 수 없는 케이스가 있다면 다음과 같이 처리한다.

  1. 가장 작은 범위로 @SuppressWarnings() 사용

  2. 이유를 주석이나 문서로 꼭 작성

배열보다 List 쓰기

공변, 불변

배열은 공변이다. 즉 Parent, Child클래스가 서로 상속관계에 있다면, Parent[], Child[]도 서로 캐스팅이 가능하다. 반대로 리스트는 불변이다.

그에 따라 배열은 문제가 생길 수 있는데, 예를 들어 한 부모 아래에 두 자식 클래스가 있고, 서로 호환이 안 되는 경우이다.

Object[] objArr = new Long[1];
objArr[0] = "wrong"; // ArrayStoreException 발생

위와 같은 예제에서 우리는 런타임까지 가서야 잘못되었다는 것을 알 수 있다.

List<Object> objList = new List<Long>(1); // 컴파일 에러 발생

반면에 리스트를 사용하면 컴파일 단계에서 그런 문제를 막아준다.

바운드 와일드카드

PECS

producer - extends, consumer - super

매개변수를 받아서 새로운 인스턴스를 생성하는 경우에는 보통 와일드카드에 extends, 매개변수를 받아서 그 매개변수를 그대로 쓰는 경우에는 보통 와일드카드에 super 바운드 지정

반환 타입에는 와일드카드 사용하지 않기

와일드카드로 얻어지는 유연성보다 해당 api를 사용하는 모든 코드가 와일드 카드 타입을 써야하는 부작용이 더 크다.

Heterogeneous Container

제네릭을 쓰는 컨테이너 객체들은 제한된 타입의 객체만 가질 수 있다. 예를 들면 List<String>은 String.class만 가질 수 있는 것과 같다. 그런데 좀 더 유연하게 다양한 타입들을 저장할 필요성이 있다면 고려해볼 수 있는 것이 바로 혼성 컨테이너이다. 혼성 컨테이너는 클래스 자체에 제네릭을 거는 대신에 key에 제네릭을 걸어둔 컨테이너다. 주로 Class<T> 타입을 키로 사용한다. 이렇게 하면 타입 안전이 보장되면서 동시에 다양한 타입들을 동시에 다룰 수 있다.

혼성 컨테이너에 어떤 객체를 저장하면 그 순간 타입에 대한 정보를 잃게 된다. 왜냐하면 자바는 제네릭 정보를 런타임에 유지하지 않기 때문이다. 그렇게 때문에 그 객체를 다시 반환할 때 타입 정보를 부여해야한다. 이 때 Class.cast() 를 사용해서 캐스팅하게 되면 unchecked warning 없이도 적절하게 체크하여 변환할 수 있다.

물론 이러한 혼성 컨테이너의 키에 Class<?> 를 사용하게 되면 List<String> 과 List<Integer> 를 구별 못하는 문제는 있다. 둘 다 List 로 인식되기 때문이다.

Previous4장Next6장 - Enum, Annotation

Last updated 7 years ago