맞는데 왜 틀릴까..?

Java/Effective Java 77

[Effective Java] Item 42. 익명 클래스보다는 람다를 사용하라

익명 클래스 자바에서 익명 클래스는 이름이 없는 클래스로, 일회성으로 사용되는 클래스를 간편하게 정의할 수 있는 기능이다. 익명 클래스는 클래스 선언과 동시에 인스턴스를 생성하여 사용한다. 주로 인터페이스나 추상 클래스를 구현하거나 확장하는 데 사용되는데, 이를 이용하면 클래스를 별도로 정의하고 이름을 부여하지 않고도 필요한 구현을 작성할 수 있다. 익명 클래스 예 문자열을 길이순으로 정렬하는데, 정렬을 위한 비교 함수로 익명 클래스를 사용하였다. 람다 익명 클래스 방식은 코드가 너무 길기 때문에 람다식을 이용해 어떤 동작을 하는지 명확하게 나타낼 수 있도록 하자. 람다식을 함수 객체로 사용한 예제 위 익명 클래스로 작성한 정렬을 람다식으로 대체한 예제이다. 람다, 매개변수, 반환값의 타입은 각각 Com..

Java/Effective Java 2023.07.02

[Effective Java] Item 41. 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라

마커 인터페이스 마커 인터페이스 : 아무 메서드도 담고 있지 않고, 단지 자신을 구현하는 클래스가 특정 속성을 가짐을 표시해 주는 인터페이스 Ex) Serializable은 자신을 구현한 클래스의 인스턴스는 ObjectOutputStream을 통해 직렬화 할 수 있다고 알려준다. 마커 인터페이스는 두 가지면에서 마커 애너테이션 보다 낫다. 1. 마커 인터페이스는 이를 구현한 클래스의 인스턴스들을 구분하는 타입으로 쓸 수 있으나, 마커 애너테이션은 그렇지 않다. 마커 인터페이스는 어엿한 타입이기 때문에, 마커 애너테이션을 사용했다면 런타임에야 발견될 오류를 컴파일 타임에 잡을 수 있다. 자바의 직렬화는 Serializable 마커 인터페이스를 보고 그 대상이 직렬화할 수 있는 타입인지 확인한다. 위 예에서..

Java/Effective Java 2023.06.30

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

@Override 애너테이션의 장점 아래 코드는 어떤 문제가 있을까? 중복을 허용하지 않는 Set에 26개의 소문자를 10번 반복해 추가했으니 집합의 크기는 26이 출력되어야 하지만 260이 출력된다. 해당 equals는 재정의(overriding)한것이 아니라 다중정의(overloading) 한 것이다. Object의 equals를 재정의하려면 매개변수 타입을 Object로 해야 하는데 그렇지 않아서 별개인 equals를 새로 정의한 것이 되었다. Object의 equals는 == 연산자처럼 객체 식별성만을 확인하여 같은 문자를 소유한 바이그램 10개가 각각 서로 다른 객체로 인식되어 260을 출력한 것이다. 여기서 만약 @Override를 달았다면 컴파일러가 해당 오류를 찾아내주었을 것이다. 이렇게 ..

Java/Effective Java 2023.06.30

[Effective Java] Item 39. 명명 패턴보다 애너테이션을 사용하라

명명 패턴의 단점 테스트 메서드 이름을 test로 시작했을 때 단점 (명명 패턴) 오타 - 실수로 tsetSafetyOverride로 지으면 테스트 프레임워크가 무시하고 지나친다 올바른 프로그램 요소에서만 사용되리라 보증할 방법이 없다. (클래스 이름을 TestSafetyMechanisms로 지었을 때 Junit은 클래스 이름에 관심이 없다.) 프로그램 요소를 매개변수로 전달할 방법이 없다. (특정 예외를 던져야만 성공하는 테스트가 있을 때, 기대하는 예외 타입을 테스트에 전달해야 한다.) Test 애너테이션 메타애너테이션 애너테이션 선언에 다는 애너테이션이다. Ex) @Retention(RetentionPolicy.RUNTIME) : @Test가 런타임에도 유지되어야 한다는 표시 @Target(Elem..

Java/Effective Java 2023.06.30

[Effective Java] Item 38. 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라

열거 패턴의 확장 타입 안전 열거 패턴은 열거한 값들을 그대로 가져온 다음 값을 더 추가하여 다른 목적으로 쓸 수 있지만 열거 패턴은 그럴 수 없다. 열거 타입을 확장하는 것은 좋지 않은 선택이지만 연산 코드 등 최소한의 쓰임새가 있다. 타입 안전 열거 패턴 타입 안전 열거 패턴은 열거 타입을 확장하여 더 많은 기능과 유연성을 제공하는 방식이다. 추가 정보를 가지는 필드와 메서드를 사용하여 상수에 대한 정보를 표현할 수 있고, 상수 집합을 제한하여 원하는 인스턴스만 생성할 수 있다. 이에 반해, 일반적인 열거 타입은 단순한 상수 값의 집합으로 사용되며, 추가 정보나 인스턴스 생성 제한 기능은 제공하지 않는다. 타입 안전 열거 패턴의 경우 ExtendedOperation 클래스를 정의하고 각 상수를 해당 ..

Java/Effective Java 2023.06.29

[Effective Java] Item 37. ordinal 인덱싱 대신 EnumMap을 사용하라

Ordinal ordinal은 Enum 타입의 객체에서 사용되는 메서드로 Enum 상수가 정의된 순서를 반환한다. Enum 상수는 0부터 시작하는 정수값을 가지며, 상수가 정의된 순서대로 0부터 1씩 증가한다. 해당 예제는 Weekday라는 Enum 타입을 정의하였으며, ordinal 메서드를 사용하여 WEDNESDAY 상수의 순서를 반환해 2를 출력한다. ordinal()을 배열 인덱스로 사용 시 문제점 이처럼 배열이나 리스트에서 원소를 꺼낼 때 ordinal 메서드로 인덱스를 얻는 코드가 있다. 해당 코드는 집합들을 배열하나에 넣고 enum의 ordinal 값을 그 배열의 인덱스로 사용하는 경우이다. 배열은 제네릭과 호환되지 않으니 비검사 형변환을 수행해야 한다. 배열은 인덱스의 의미를 모르니 출력 ..

Java/Effective Java 2023.06.29

[Effective Java] Item 36. 비트 필드 대신 EnumSet을 사용하라

열거한 값들이 주로 단독이 아닌 집합으로 사용될 경우, 예전에는 각 상수에 서로 다른 2의 거듭제곱 값을 할당한 정수 열거 패턴을 사용해 왔다. 비트 필드 비트 필드 열거 상수 아래처럼 비트별 OR를 사용해 여러 상수를 하나의 집합으로 모을 수 있으며, 이렇게 만들어진 집합을 비트 필드라 한다. text.applyStyles(STYLE_BOLD | STYLE_ITALIC); 비트 필드를 사용하면 비트별 연산을 사용해 합집합과 교집합 같은 집합 연산을 효율적으로 수행할 수 있다. 비트 필드는 정수 열거 상수의 단점을 그대로 지닌다. 비트 필드 값이 그대로 출력되면 단순한 정수 열거 상수를 출력할 때보다 해석하기 훨씬 어렵다. 비트 필드 하나에 녹아 있는 모든 원소를 순회하기도 까다롭다. 최대 몇 비트가 필..

Java/Effective Java 2023.05.16

[Effective Java] Item 35. ordinal 메서드 대신 인스턴스 필드를 사용하라

가뭄에 단비 같은 아이템이구나.. 대부분의 열거 타입 상수는 자연스럽게 하나의 정숫값에 대응된다. 모든 열거 타입은 해당 상수가 그 열거 타입에서 몇 번째 위치인지를 반환하는 ordinal 메서드를 제공한다. 이런 이유로 열거 타입 상수와 연결된 정숫값이 필요하면 ordinal 메서드를 이용하고 싶은 생각이 들 수 있다. 하지만 ordinal 메서드는 많은 단점이 있다. 합주단 종류를 연주자가 1명인 SOLO 부터 10명인 DECTET까지 정의한 열거 타입 동작은 하지만 유지보수하기 힘들다. 상수 선언 순서를 바꾸면 numberOfMusicians가 오작동한다. 이미 사용 중인 정수와 값이 같은 상수는 추가할 수 없다. (8중주가 이미 있으므로 똑같이 8명이 연주하는 복4중주는 추가할 수 없다.) 값을 ..

Java/Effective Java 2023.05.16

[Effective Java] Item 34. int 상수 대신 열거 타입을 사용하라

정수 열거 패턴 자바에서 열거 타입을 지원하기 전에는 다음 코드처럼 정수 상수를 한 묶음으로 선언해서 사용했다. public static final int APPLE_FUJI = 0; public static final int APPLE_PIPPIN = 1; public static final int APPLE_GRANNY_SMITH = 2; public static final int ORANGE_NAVEL = 0; public static final int ORANGE_TEMPLE = 1; public static final int ORANGE_BLOOD = 2; 하지만 이 정수 열거 패턴은 상당히 취약하다. 1. 타입 안전을 보장할 방법이 없으며 표현력도 좋지 않다. 오렌지를 건네야 할 메서드에 사과..

Java/Effective Java 2023.05.16

[Effective Java] Item 33. 타입 안전 이종 컨테이너를 고려하라

타입 안전 이종 컨테이너란, 제네릭을 이용하여 서로 다른 타입의 객체를 담을 수 있는 컨테이너를 말한다. 즉, 컨테이너 내부에 저장된 객체들이 모두 같은 타입일 필요가 없으며, 다양한 타입의 객체들을 함께 보관하면서도 타입 안정성을 보장할 수 있다. 컨테이너(Container) 컨테이너란 객체를 담는 역할을 하는 클래스를 의미한다. 일반적으로 다수의 객체를 담을 수 있는 객체를 말하며, 주로 배열(Array)과 컬렉션(Collection)이 포함된다. 타입 안전 이종 컨테이너 패턴 컨테이너 대신 키를 매개변수화한 다음, 컨테이너에 값을 넣거나 뺄 때 매개변수화한 키를 함께 제공하면 제네릭 타입 시스템이 값의 타입이 키와 같음을 보장해 준다. 타입별로 즐겨 찾는 인스턴스를 저장하고 검색할 수 있는 Favo..

Java/Effective Java 2023.05.16