Dev 47

[Effective Java : Item 58] 전통적인 for 문보다는 for-each 문을 사용하라

for 문 // for 문으로 컬렉션 순회 for (Iterator i = c.iterator(); i.hasNext(); ) { Element e = i.next(); ... // 부수적인 동작 } // for 문으로 배열 순회 for (int i = 0; i < a.length; i++) { ... // 부수적인 동작 } 위 코드는 for 문으로 컬렉션과 배열을 순회하는 코드이다. 이러한 순회 방식은 while 보다는 낫지만, 몇 가지 단점이 존재한다. 단점 1. 가독성 반복자와 인덱스 변수는 가독성을 해친다. 또한 원소만 필요한 경우 원소 반환 목적 외에는 의미가 없는 코드이다. 2. 휴먼 에러 반복자와 인덱스가 많은 빈도로 등장하여 변수를 잘못 사용할 가능성이 높아진다. 또한 컴파일러가 잘못 사용..

Dev/Java 2024.03.18

[Effective Java : Item 55] 옵셔널 반환은 신중히 하라

개요 자바 8 이전, 즉 Optional이 존재하기 이전에는 메서드가 특정 조건에서 값을 반환하지 못할 때 취할 수 있는 두 가지 선택지가 있었다. 하지만 각각 가지고 있는 허점이 존재했다. 1. 예외를 던진다. 예외는 되도록 진짜 예외인 상황에서만 사용해야 하고, 예외가 발생할 때 스택 추적 전체를 캡쳐하므로 다소 비용이 크다. 2. null을 반환한다. 별도의 null 처리를 해야 한다. 그렇지 않다면 언젠가 null이 발생한 근원지와는 상관없는 곳에서 NullPointException이 발생할 것이다. 위같은 문제를 해결하기 위해 Optional이 등장했다. Optional Optional는 null이 아닌 T 타입 참조를 하나 담거나, 아무것도 담지 않을 수 있다. 또한 Optional는 위와 같..

Dev/Java 2024.03.14

[Effective Java : Item 51] 메서드 시그니처를 신중히 설계하라

개요 메서드 시그니처란, 메서드의 이름과 매개변수 타입 리스트의 조합을 말한다. 이름이 같은 메서드라도 매개변수 리스트의 타입 순서나 구성이 다르다면 서로 다른 메서드 시그니처로 판단된다. 아이템 51에서는 메서드 시그니처와 관련된 API 설계 요령들을 간략하게 모아 소개한다. API 설계 요령 메서드 이름을 신중히 짓자(아이템 68). - 항상 표준 명명 규칙을 따라야 한다. - 같은 패키지에 속한 다른 이름들과 일관되게 지어야 한다. - 개발자 커뮤니티에서 널리 받아들여지는 이름을 사용하자. - 너무 긴 이름은 피하자. - 어렵다면 자바 라이브러리 API 가이드를 참조해도 좋다. 편의 메서드를 너무 많이 만들지 말자. - 메서드가 너무 많은 클래스 및 인터페이스는 익히고, 사용하고, 문서화하고, 테스..

Dev/Java 2024.03.12

[Effective Java : Item 44] 표준 함수형 인터페이스를 사용하라

개요 상위 클래스의 메서드를 재정의해 원하는 동작을 직접 구현하는 것보다, 같은 효과의 함수 객체를 매개변수로 받는 메서드나 생성자를 제공하는 것은 보다 큰 유연함을 제공한다. LinkedHashMap 클래스의 protected 메서드인 removeEldestEntry를 예시로 살펴보도록 하자. protected boolean removeEldestEntry(Map.Entry eldest) { return false; } 새로운 원소를 추가하는 put 메서드는 이 메서드를 호출하여 true가 반환될 경우 가장 오래된 원소 하나를 제거한다. 이를 활용하여 원소의 최대 개수를 제한해 맵을 캐시처럼 사용할 수 있다. public class CustomLinkedHashMap extends LinkedHashM..

Dev/Java 2024.03.06

[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..

Dev/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..

Dev/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 배열에 들어갈 수 없기 때문이다. 반면, 제네릭은 불공변이다. 서로 다른 두 제네릭 타입이 있을 때, 그 타입 간의 상속 관계와는 무..

Dev/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..

Dev/Java 2024.02.13

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

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

Dev/Java 2024.02.12
반응형