아이템 57: 지역변수의 범위를 최소화하라
자바는 문장을 선언할 수 있는 곳이면 어디든 변수를 선언할 수 있기 때문에 가장 처음 쓰일 때 선언하는 것이 좋으며, 스코프가 오염되는 것을 방지할 수 있다.
지역변수 초기화 시점
- 거의 모든 지역변수는 선언과 동시에 초기화해야 한다.
- 예외적으로 try-catch를 사용할 때는 try 블록 안에서 초기화해야 한다.
반복문은 while 문보다는 for 문을 사용하자
→ while 문을 사용할 때는 반복문 블록 밖에 불필요한 변수가 존재하기 때문에 잠재적인 오류 가능성이 있다.
Iterator<Element> i = c.iterator();
while (i.hasNext()) {
doSomething(i.next());
}
for (Iterator<Element> i = c.iterator(); i.hasNext(); ) {
Element e = i.next();
doSomething(e);
}
아이템 58: 전통적인 for 문보다는 for-each 문을 사용하라
자바 1.5부터 추가된 for-each 문은 전통적인 for 문보다 깔끔하고 예상치 못한 오류를 줄여 준다.
Iterable을 구현한 객체라면 무엇이든 순회 가능하다.
var list = new ArrayList<Integer>();
for (int i = 0; i < list.size(); i++) {
}
for (var item : list) {
}
for-each를 사용할 수 없는 상황
파괴적인 필터링: 컬렉션을 순회하면서 특정 원소를 제거
자바 8부터는
Collections.removeIf()
를 사용할 수 있다.변형: 컬렉션을 순회하면서 원소의 값 또는 전체를 교체
병렬 반복: 컬렉션을 병렬로 순회
아이템 59: 라이브러리를 익히고 사용하라
표준 라이브러리를 사용하면 코드를 작성한 전문가의 지식과 다른 프로그래머의 경험을 활용할 수 있다.
→ 바퀴를 재발명하지 말자.
아이템 60: 정확한 답이 필요하다면 float와 double은 피하라
float과 double 등의 부동 소수점 연산 타입은 정확한 값이 아닌 근사치를 사용하기 때문에, 정확한 값이 필요할 때는 사용하면 안 된다.
→ 느리지만 정확한 값이 필요하다면 BigInteger, BigDecimal 타입을 사용하자.
아이템 61: 박싱된 기본 타입보다는 기본 타입을 사용하라
오토박싱이 지원되기 때문에 기본 타입과 참조 타입을 큰 구분없이 사용할 수 있지만, 사용에 주의해야 한다.
기본 타입과 박싱된 기본 타입의 차이점
기본 타입은 값만 가지고 있지만, 박싱된 기본 타입은 참조 타입이기 때문에 참조 식별성이 있다.
var a = new Integer(1); var b = new Integer(1); a.equals(b); // true a == b; // false
박싱된 기본 타입은 null을 가질 수 있다.
기본 타입이 박싱된 타입보다 효율적이다.
- 박싱 타입은 참조 타입이기 때문에 무조건 메모리를 사용하지만, 기본 타입은 변수 자체에 값이 있다.
박싱된 타입 사용시 발생할 수 있는 상황들
박싱된 타입에서 동등성 비교를
equals()
대신==
를 사용해서 하게 되면 정상적으로 동작하지 않는다.기본 타입과 박싱된 타입을 혼용한 연산에서는 대부분 언박싱되므로, NPE에 주의해야 한다.
public class Unbelievable { static Integer i; public static void main(String[] args) { if (i == 42) { System.out.println("믿을 수 없군"); } } }
타입을 잘못 사용하게 되면 오토박싱으로 인한 성능 저하가 일어난다.
public static void main(String[] args) { Long sum = 0L; for (long i = 0L; i < Integer.MAX_VALUE; i++) { sum += i; } System.out.println(sum); }
매개변수화 타입의 타입 매개변수로 사용할 때, 리플렉션을 사용할 때를 제외하고는 기본 타입을 사용하는 것이 낫다.
아이템 62: 다른 타입이 적절하다면 문자열 사용을 피하라
더 적절한 타입이 있거나 새로 작성할 수 있다면 문자열을 사용하지 말고 해당 타입을 사용하자.
다른 값 타입/열거 타입/혼합 타입을 표현하기 위해 문자열을 사용하지 말아야 한다.
아이템 63: 문자열 연결은 느리니 주의하라
문자열은 불변이기 때문에, 두 문자열을 연결할 경우 양쪽의 내용을 모두 복사해야 한다.
→ 많은 문자열을 연결할 때는 문자열 연결 연산자(+) 대신 StringBuilder를 사용하자.
아이템 64: 객체는 인터페이스를 사용해 참조하라
인터페이스를 참조하면 프로그램이 훨씬 유연해진다.
- 적합한 인터페이스가 있는 경우 매개변수, 반환값, 변수, 필드 등 객체를 참조하는 모든 곳을 인터페이스 타입으로 선언하자.
- 적합한 인터페이스가 없다면 클래스의 계층구조 중 필요한 기능을 만족하는 가장 상위 클래스를 타입으로 사용하자.
아이템 65: 리플렉션보다는 인터페이스를 사용하라
리플렉션은 강력하지만, 장황하고 오류를 만들기 쉽기 때문에 아주 제한된 형태로만 사용해야 한다.
리플렉션으로 인스턴스를 생성하는 경우 인터페이스나 상위 클래스로 참조해 사용하는 것이 좋다.
리플렉션의 단점
- 컴파일타임 타입 검사의 이점을 누릴 수 없다.
- 코드가 지저분하고 장황해진다.
- 성능이 떨어진다.
// 리플렉션으로 활용한 인스턴스화 데모
public class ReflectiveInstantiation {
// 코드 65-1 리플렉션으로 생성하고 인터페이스로 참조해 활용한다. (372-373쪽)
public static void main(String[] args) {
// 클래스 이름을 Class 객체로 변환
Class<? extends Set<String>> cl = null;
try {
cl = (Class<? extends Set<String>>) // 비검사 형변환!
Class.forName(args[0]);
} catch (ClassNotFoundException e) {
fatalError("클래스를 찾을 수 없습니다.");
}
// 생성자를 얻는다.
Constructor<? extends Set<String>> cons = null;
try {
cons = cl.getDeclaredConstructor();
} catch (NoSuchMethodException e) {
fatalError("매개변수 없는 생성자를 찾을 수 없습니다.");
}
// 집합의 인스턴스를 만든다.
Set<String> s = null;
try {
s = cons.newInstance();
} catch (IllegalAccessException e) {
fatalError("생성자에 접근할 수 없습니다.");
} catch (InstantiationException e) {
fatalError("클래스를 인스턴스화할 수 없습니다.");
} catch (InvocationTargetException e) {
fatalError("생성자가 예외를 던졌습니다: " + e.getCause());
} catch (ClassCastException e) {
fatalError("Set을 구현하지 않은 클래스입니다.");
}
// 생성한 집합을 사용한다.
s.addAll(Arrays.asList(args).subList(1, args.length));
System.out.println(s);
}
private static void fatalError(String msg) {
System.err.println(msg);
System.exit(1);
}
}
아이템 66: 네이티브 메서드는 신중히 사용하라
자바는 JNI를 통해 네이티브 코드에 접근할 수 있지만, 사용에 신중해야 한다.
- 네이티브 메서드가 성능을 개선하는 일은 많지 않으며, 디버깅 용이성과 이식성을 저하시킨다.
- 네이티브 코드는 안전하지 않기 때문에 네이티브 메서드를 사용하는 애플리케이션도 메모리 훼손 오류로부터 안전하지 않다.
아이템 67: 최적화는 신중히 하라
- 빠른 프로그램보다는 좋은 프로그램이 낫다.
- 성능을 제한하는 설계를 피하라.
- API를 설계할 때 성능에 주는 영향을 고려하라.
- 하지만 성능을 위해 API를 왜곡하면 안 된다.
- 최적화 시도 전후로 성능을 측정하자.
아이템 68: 일반적으로 통용되는 명명 규칙을 따르라
표준 명명 규칙을 습관화하자.