자바 27

[Effective Java : Item 40] @Override 애너테이션을 일관되게 사용하라

개요 가장 흔히 볼 수 있는 애너테이션인 @Override는 상위 타입의 메서드를 재정의했음을 뜻한다. 이를 메서드를 재정의하고자 한다면 항상 일관되게 사용하는 것을 권장한다. @Override 애너테이션을 사용하지 않았을 때 발생할 수 있는 버그 예시는 다음과 같다. public class Bigram { private final char first; private final char second; public Bigram(char first, char second) { this.first = first; this.second = second; } public boolean equals(Bigram b) { return b.first == first && b.second == second; } publ..

Backend/Java 2024.03.05

[Effective Java : Item 32] 제네릭과 가변인수를 함께 쓸 때는 신중하라

개요 가변인수(varargs)란 다음과 같이 명시한 타입의 인수를 0개 이상 받을 수 있는 것을 의미한다. static int sum(int... args) { int sum = 0; for (int arg : args) sum += arg; return sum; } 메서드가 호출되면 인수의 개수와 길이가 같은 배열을 생성한 뒤 인수들을 이 배열에 저장하여 가변인수 메서드에 건네준다. 그런데 이 배열은 자바의 내부에서만 동작하지 않고 클라이언트 코드로 노출되었다. 여기서, Item 28 에서 자세히 언급한 문제가 발생할 가능성이 생기게 된다. 제네릭 배열 static void dangerous(List... stringLists) { List intList = List.of(42); Object[] ob..

Backend/Java 2024.02.22

[Effective Java : Item 28] 배열보다는 리스트를 사용하라

배열 vs 제네릭(리스트) 1. 공변 vs 불공변 (공변: 함께 변함) 배열은 공변이다. 즉, Sub가 Super의 하위 타입이라면 배열 Sub[]는 배열 Super[]의 하위 타입이 된다. 그렇기 때문에 다음은 문법 상 허용되는 배열 코드이다. Object[] objectArray = new Long[1]; objectArray[0] = "타입이 달라 넣을 수 없음"; // ArrayStoreException 발생 위 코드는 문법상 허용되어 컴파일 타임에 예외가 일어나지 않지만, 실제로 스트링이 배열에 들어갈 때 런타임 오류가 발생한다. 당연하게도 String은 Long 배열에 들어갈 수 없기 때문이다. 반면, 제네릭은 불공변이다. 서로 다른 두 제네릭 타입이 있을 때, 그 타입 간의 상속 관계와는 무..

Backend/Java 2024.02.18

[Effective Java : Item 23] 태그 달린 클래스보다는 클래스 계층구조를 활용하라

태그 달린 클래스 태그 값을 통해 현재 표현하는 의미가 무엇인지 결정하는 클래스 형태가 있다. 아래는 그 예이다. class Figure { enum Shape {RECTANGLE, CIRCLE} // 태그 필드 - 현재 모양을 나타낸다. final Shape shape; // 모양이 사각형(RECTANGLE)일 때만 쓰이는 필드 double length; double width; // 모양이 원(CIRCLE)일 때만 쓰이는 필드 double radius; // 원용 생성자 Figure(double radius) { shape = Shape.CIRCLE; this.radius = radius; } // 사각형용 생성자 Figure(double length, double width) { shape = Sh..

Backend/Java 2024.02.13

[Effective Java : Item 19] 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라

개요 상속용 클래스 혹은 상속이 가능한 클래스를 설계할 때 고려해야 할 규약이 몇 가지 있다(여기서의 상속은 extends로 확장하는 구현 상속을 의미). 문서화하는 것, 충분한 검증이 이루어져야 하는 것, 그리고 몇 가지 구현상의 제약이다. 상속용 클래스를 설계하는 것은 많은 노력이 들고 그 클래스에 안기는 제약 또한 많으므로 설계 전 충분한 고민이 필요하다. 상속 대신 컴포지션을 사용하는 방법을 고려하는 것(아이템 18)도 그 고민 중 하나일 것이다. 상속을 고려하지 않은 일반적인 클래스를 작성할 때에도 여전히 누군가 임의로 확장해서 사용할 가능성이 있다. 따라서 이를 방지하기 위해 일반 클래스를 누군가 상속하지 못하도록 조치를 취해야 한다. 상속용 클래스 작성 규약 1. 상속용 클래스는 재정의할 수..

Backend/Java 2024.02.12

[Effective Java : Item 12] toString을 항상 재정의하라

개요 Object 클래스에서 기본으로 작성된 toString 메서드는 PhoneNumber@adbbd 처럼 단순히 '클래스 이름@16진수 해시코드' 로 반환한다. // Object의 toString 기본 메서드 public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } 하지만 위에서 언급한 형태보다는 010-1234-5678 처럼 실제 그 클래스의 핵심적인 정보를 읽기 쉬운 형태로 제공하는 것이 좋을 것이다. 이는 toString의 일반 규약이고, 실제로 모든 Object의 하위 클래스는 toString을 재정의하라고 규약을 정의하고 있다. 개발자가 직접 toString을 사용하지 않더라도..

Backend/Java 2024.02.04

[Effective Java : Item 4] 인스턴스화를 막으려거든 private 생성자를 사용하라

개요 프로젝트 내에 정적 메서드와 정적 필드만을 담은, 예를 들면 java.lang.Math나 java.util.Arrays 같은 클래스를 생성하고 싶을 수 있다. 이러한 유틸리티 클래스는 인스턴스로 만들어 사용하고자 하는 것이 아니지만, 생성자를 명시하지 않으면 컴파일러가 자동으로 매개변수가 없는 기본 생성자를 만들어주기 때문에 인스턴스화될 여지가 있다. 따라서 생성자를 private으로 선언해줌으로써 인스턴스화를 방지할 수 있다. 아이템 1에서 소개되었던 내용이기도 하다. 만약 클래스를 추상 클래스로 만든다면 인스턴스화되지 않기는 하지만, 이는 완벽하게 인스턴스화를 막는 방법이 아니다. 클래스를 상속해서 인스턴스화 하면 되기 때문이다. 그리고 이런 방법은 명시적인 설명이 없다면 오히려 상속해서 사용하..

Backend/Java 2024.01.30

[Effective Java : Item 3] private 생성자나 열거 타입으로 싱글턴임을 보증하라

개요 싱글턴(singleton)이란 디자인 패턴 중 하나로, 인스턴스를 오직 하나만 가질 수 있도록 보장하는 클래스를 말한다. 싱글턴의 예로는 무상태(stateless) 객체나 설계상 유일해야 하는 시스템 컴포넌트를 들 수 있다. @Service, @Controller 등으로 생성되는 스프링 빈 또한 싱글턴의 일종이다. 싱글턴을 생성하는 방법은 여러 가지가 있는데, 아래 3가지 방식에 대해 소개한다. public static final 필드 방식(Eager Initialization) 정적 팩터리 방식 열거 타입 방식(Enum Initialization) 1번과 2번 방식이 싱글턴을 만들 때 일반적으로 사용되지만, 이펙티브 자바의 저작자는 열거 타입 방식이 대부분의 상황에서 가장 좋은 방법이라 말한다. ..

Backend/Java 2024.01.24

[Effective Java : Item 2] 생성자에 매개변수가 많다면 빌더를 고려하라

개요 생성자와 정적 팩터리 메서드에는 공통적인 제약이 하나 있는데, 바로 매개변수가 많을 경우 적절히 대응하기 힘들다는 점이다. 식품 포장의 영양정보를 표현하는 클래스가 있다고 가정하자. 이 클래스에는 다양한 영양 정보를 표시하기 위해 수많은 필드들이 있을 것이다. 만약 특정 식품 포장에 영양정보를 표현하기 위해 이 클래스를 사용한다면 대부분의 제품은 필수 값을 제외하고 선택 항목들의 값이 0이 될 것이다. 위와 같은 문제를 해결하기 위해 다음과 같은 대안이 있다. 점층적 생성자 패턴(telescoping constructor pattern) 자바 빈즈 패턴(JavaBeans pattern) 빌더 패턴(Builder pattern) 빌더 패턴이 가장 권장되는 것처럼 제목에서부터 언급하지만, 그 이유를 알..

Backend/Java 2024.01.19
반응형