본문 바로가기
책(독서)

[이펙티브자바] ~169p item 25~28

by DevJR 2020. 10. 20.

아이템 25 - 톱 레벨 클래스는 한 파일에 하나만 담으라

 

Main.class

public class Main {
	public static void main(String [] args) {
    	System.out.println(Cooking.Name + Food.Name);
    }
}

 

Cooking.class 클래스에(톱클래스) Cooking과 Food 클래스 모두 정의되어 있을 때,

class Cooking {
	static final String NAME = "fried";
}

class Food {
	static final String NAME = "egg";
}

 

우연하게도 똑같은 두개의 클래스를 담은 Food.java 파일 생성시

javac Main.java Food.java 명령으로 컴파일 하면 컴파일 오류 발생

 

이와 같은 컴파일 오류를 미연에 막기 위해서는 애초에 하나의 파일에 톱 클래스 여러개를 선언하지 말거나, 굳이 한 파일에 담고자 할 때에는 다음과 같이 정적 멤버 클래스로 선언해서 사용한다.

 

public class Test {
	public static void main(String [] args) {
    	System.out.println(Cooking.NAME + Food.NAME);
    }
    
    private static class Cooking {
    	static final String NAME = "fried";
    }
    
    private static class Food {
    	static final String NAME = "egg";
    }
}

아이템 26 - 로 타입은 사용하지 말라

 

-> 로 타입 : 타입 매개변수가 없는 제네릭 타입

     ex> List<E> 의 로타입은 List

-> 로 타입처럼 제네릭 타입이 아예 명시되어 있지 않으면 컴파일 단계에서 컬렉션 등에 잘못된 데이터가 들어가더라도 파악이 힘들다. 제네릭 타입을 명시해주면 이와 같이 타입에 위배되는 요소를 컴파일 단계에서 알 수 있다.

-> 로 타입이 허용된 이유는 기존에 자바에서는 제네릭 타입이 존재하지 않았기 때문에 기존 자바 사용자들을 위함이다.

-> 즉, 로 타입을 쓰지 말고 제네릭 타입을 꼭 명시해주는 것이 좋다는 의미이다.

 

-> 예외)

1. class 리터럴에는 로 타입을 써야 한다. (배열과 기본 타입 제외)

  •  List.class, String[].class, int.class 허용
  •  List<String>.class, List<?>.class 허용하지 않음.

2. instanceof 연산자는 로 타입을 쓰는 편이 낫다. (런타입에는 제네릭 타입 정보가 지워지므로) 159p

 

아이템 27 - 비검사 경고를 제거하라

 

-> 아래와 같이 선언하고 javac를 하게 되면 비검사 경고가 뜬다고 한다.

Set<Sun> sunSet = new HashSet();

HashSet쪽에 경고가 뜨는데, 다음과 같이 변경하면 경고가 사라진다고 한다.

Set<Sun> sunSet = new HashSet<>();

(다이아몬드 연산자(<>) 를 사용하면 실제 타입을 선언하지 않아도, Sun이라는 타입 매개변수를 추론해준다.)

 

이런식으로 경고들을 제거해주면 런타임시 ClassCastException이 발생하지 않고 코드 작성자 의도대로 코드가 잘 실행될 것이다.

경고를 제거할 수는 없으나, 타입이 안전하다고 확신이 가능하면 @SuppressWarnings("unchecked") 애노테이션을 달아서 경고를 숨길 수 있다.

이 애노테이션은 개별 지역변수 선언부터 클래스 전체까지 어떤 선언에도 달 수 있으나, 되도록 좁은 범위에 적용하도록 하는게 좋다. 또한, 이 애노테이션을 달아서 경고를 무시해도 되는 이유를 주석으로 꼭 남겨야 한다.

 

아이템 28 - 배열보다는 리스트를 사용하라

 

배열 사용시

Object[] objArr = new Long[2];
objArr[0] = "문자열 들어가는지?"; //ArrayStoreException 발생

 

리스트 사용시

List<Object> objList = new ArrayList<Long>(); //컴파일 오류
objList.add("문자열 넣어보기");

 

이와 같이 배열은 제네릭 타입, 매개변수화 타입, 타입 매개변수로 사용할 수 없다.

결국 타입 안정성을 추구하고자 하거나, 비검사 경고가 뜰 때에는 배열말고 리스트를 고려하는 것이 낫다.