본문 바로가기

effectivejava

한정적 와일드카드를 사용해 API 유연성을 높이라 매개변수화 타입은 불공변이다. List 은 List 의 하위 타입이 아니다. 매개변수 타입이 List 라고 명시가 되어 있으면 무조건 List 만 넘겨야 한다. 유연성을 극대화하려면 원소의 생산자나 소비자용 입력 매개변수에 와일드카드 타입을 사용하라 매개변수에 Collection 라는 타입만 명시를 하면 E타입이 상속하거나 E타입을 상속하는 타입 또한 매개변수로 넘길 수 없다. 매개변수 타입 T가 생성자라면 를 사용하고, 소비자라면 를 사용해라. Comparable, Comparator는 모두 소비자 public static < E extends Comparable<.. 더보기
비검사 경고를 제거하라 제네릭 타입을 사용을 하면 컴파일 당시에 잡히지 않는 런타임 에러에 취약하다. 그 이유는 타입이 정해져 있지 않기 때문에 타입 변환, 특정 타입 메서드 사용할 때 런타임 에러가 발생한다. 이런 점 때문에 컴파일러가 제니릭 타입에 대한 비검사 경고를 알려준다. 비검사 경고가 로그에 출력이 되었다고 컴파일이 되지 않는 것은 아니지만 무시하고 넘길만한 내용도 아니다. 해결할 수 있는 내용이면 해결하고 만약 해결을 안해도 되는 내용이라면 @SuppressWarnings("unchecked")를 사용해서 경고를 숨기도록 하자. 더보기
로 타입은 사용하지 말라 자바 기본라이브러리에 있는 클래스나 인터페이스에 간간히 타입이 명시 되어 있는 경우가 있다. 이런 클래스나 인터페이스를 제네릭 클래스 혹은 제네릭 인터페이스라고 부른다. public interface List extends Collection { } 위의 코드를 예로 들면 List 인터페이스이다. 여기서 E가 의미하는 바는 무엇일까? 리스트를 사용할 때 List 안에 들어가는 객체는 Object, String, Integer 등등 사용할 때마다 변경이 될 수 있다. 그렇기 때문에 특정 타입으로 명시할 수 없으므로 List를 생성할 때 타입을 넣어서 사용하는 용도이다. 만약에 사용할 때 타입을 명시를 안 하면 어떻게 될까?? 궁금증이 생길 수 있다. 일단 그렇게 사용하는 것을 로 타입이라고 부르고 실제로도.. 더보기
톱레벨 클래스는 한 파일에 하나만 담으라 // 1.Utensil.java class Utensil { static final String NAME = "AHN"; } class Desert { static final String NAME = "AHN"; } // 2.Desert.java class Desert { static final String NAME = "WOO"; } class Utensil { static final String NAME = "WOO"; } 첫 번째는 Utensil.java에 Utensil, Desert 클래스가 정의가 되어 있고 두 번째는 Desert.java에 Desert, Utensil 클래스가 정의되어 있다.위의 경우에는 문제점이 2가지가 있다. 문제점 1. xxx.java 파일에 여라 개에 톱레벨 클래스가 존.. 더보기
태그 달린 클래스보다는 클래스 계층구조를 활용하라 개발을 할 때 기존 클래스에 내용을 추가하고 싶을 때가 있을 것이다. 그럴 때 공통적으로 사용하는 필드값을 추가하는 것은 문제가 되지 않는다. 문제가 되는 것은 클래스 안에 새로운 객체를 두고 분기를 두어서 사용하는 것이다. 처음에는 좋을 수도 있지만 계속 클래스를 확장해 가면 분기를 하는 부분을 계속 변경해야 하고 이것을 놓칠 시에는 컴파일 에러가 아닌 위험한 런타임 에레가 발생한다. 이런 점 때문에 태그 달린(클래스 내부의 객체)를 사용하지 말고 공통 정인 메서드를 추상 클래스의 초상 메서드로 만들고 상속을 해서 사용하는 것이 좋다. 아이템 23을 읽으면서 느낀 것은 하나의 클래스는 한 가지 의미를 가져야 하고 의미가 많아지면 관리하기가 힘들어진다. 더보기
인터페이스는 타입을 정의하는 용도로만 사용하라 인터페이스를 설계하는 이유는 여러 개가 있지만 그중에서 가장 큰 이유는 인터페이스를 구현하는 클래스에 메서드 이름, 매개변수, 반환 타입을 정할 수 있다. 이처럼 타입이 정해져 있기 때문에 인터페이스를 구현하고 있는 클래스끼리는 코드에서 변경하기 수월하다.(다형성) 인터페이스는 구현하는 클래스를 타입을 정의할 때만 사용해야 하는데 인터페이스를 통해 공통 상수를 제공하는 경우도 있다. public interface PhysicalConstants { static final AVOGADROS_NUMBER = 6.022_140_857e23; static final double BOLTZMANN_CONSTANT = 1.380_648_52e-23; } 인터페이스를 통해서 공통 상수를 제공하는 것보다 특정 Util.. 더보기
public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 public class 에서 public 필드를 사용하면 어떻게 될까? 처음에 Class 를 배울 때 필드에 접근 제어자 private 를 쓰라고 배웠다. 근데 왜 private 를 사용해야 할까? 일단 밑에 코드를 보자. pulbic class Point { public int pointX; public int pointY; } 위에 Point의 pointX, pointY 값에 접근할 때 Point 객체를 생성하고 바로 접근할 수 있다. public class Client{ public static void main() { Point point = new Point(); point.pointx = 1; point.pointy = 2; } } 이런 식으로 객체의 필드에 바로 접근할 수 있으면 무분별하게 .. 더보기
toString 을 재정의 해라. toString 메서드는 Object 클래스에 있는 메서드이다. 이 말은 모든 클래스가 가지고 있고 재정의를 할 수 있다는 것이다. toString 을 재정의 해야하는 이유 1.toString 을 재정의 하지 않으면 클래스 이름 + @ 16진수 해시코드가 나온다.일반적인 상황에서는 필요 없는 정보이다. 2.toString 은 개발자가 호출을 하지 않아도 자동으로 호출되는 상황이 있다.(ex 디버깅) 3.toString 을 개발자가 보기 편하게 재정의하면 개발할 때 유용하게 이용할 수 있다. toString 재정의 할 때 유의점 1.객체에 필드를 다 표시해야 한다. 그 이유를 하나 들면 디버깅할 때 특정 필드 값을 제외하고 출력이 되면 다른 개발자에게 혼란을 줄 수 있다. 2.포맷팅을 할 거면 주석을 통해.. 더보기