목록이펙티브자바 (88)
도당탕탕
만약 적절한 인터페이스 타입이 존재할 때, 파라미터와 리턴 타입 그리고 필드들은 모두 인터페이스 타입으로 선언되어야 한다. 이유는 더 프로그램이 더 유연해지기 때문이다. 인터페이스 사용의 장점 1. 여러 구현체 사용가능 LinkedHashSet sonSet = new LinkedHashSet(); // 유연하지 않음. Set sonSet = new HashSet(); // 유연함. 위에 코드 처럼 인터페이스 타입은 여러 구현을 사용할 수 있다. 2. 구현 클래스의 변동사항에 영향을 받지 않음. 구현 클래스 타입으로 사용시, 구현 클래스가 후에 업데이트되면, 클라이언트 코드는 더 이상 동작하지 않을 수 있다. 하지만 인터페이스는 변경될 가능성이 낮다. 적절한 인터페이스가 존재하지 않을 경우 어떻게 할까? ..
문자열 연결 연산자는 +를 사용하여 문자열들을 연결시킬 수 있다. 하지만 한 줄 자리 출력값 혹은 작고 크기가 고정된 객체의 문자열 표현을 만들 때라면 괜찮지만, 본격적으로 사용하기 시작하면 성능 저하를 일으킨다. 다음 예를 보자. 문자열 연결을 잘못 사용한 예 public String statement() { String result = ""; for (int i = 0; i < numItems(); i++) { result += lineForItem(i); } return result; } 위 예제에서 문자열 연결 연산자를 사용했다. 하지만 이 메서드는 심각하게 느려지는 현상을 볼 수 있다. 그 이유는 문자열 연결 연산자는 문자열 n개를 잇는 시간이 n^2에 비례하기 때문이다. 문자열은 불변이기 때문..
보통 파일이나 네트워크로부터 데이터가 넘어오면, String 형태의 데이터인 경우가 많다. 하지만 이를 그대로 String 변수에 저장하기보다 적절한 자료형으로 저장하는 것이 좋다. String은 aggregate type을 표현하기 에는 부적절하다. String compoundKey = className + "#" + i.next() 위 처럼 표현하면 결국, className을 뽑아내기 위해서는 String을 파싱 해야 한다. 그보다는 item 24에서 배웠듯이 static class 를 사용해서 표현하는 것이 좋다. private static class CompoundKey { String className; String next; public CompoundKey(String className, S..
자바의 데이터 타입은 크게 두 가지로 나뉜다. 원시 타입 : int, double, boolean 참조 타입 : Integer, Double, Boolean 오토박싱과 오토언박싱 덕분에 두 타입을 크게 구분하지 않고 사용할 수는 있지만, 그렇다고 차이가 사라지는 것은 아니다. 둘 사이의 분명한 차이는 있으니 적절히 사용해야 한다. 기본 타입과 박싱 된 기본 타입의 주된 차이는 크게 세 가지이다. 기본 타입은 값만 가지고 있으나, 박싱 된 기본 타입은 값에 더해 식별성이란 속성을 갖는다. 달리 말하면 박싱된 기본 타입의 두 인스턴스는 값이 같아도 서로 다르다고 식별될 수 있다. 기본 타입의 값은 언제나 유효하나, 박싱된 기본 타입은 유효하지 않는 값, 즉 null을 가질 수 있다. 기본 타입이 박싱된 기본..
float, double의 문제점 float 과 double 타입은 주로 과학적, 공학적 계산에 사용되도록 설계되었다. 하지만 항상 정확한 수치를 리턴하지는 않는다. 특히 환율계산 작업에는 적합하지 않다. 왜냐하면 0.1을 정확히 표현하는 것이 불가능하기 때문이다. System.out.println(1.03 - 0.42) 위의 결과는 0.6100000000000001 이다. 그리고 System.out.println(1.00 - 9 * 0.10); 위의 결과는 0.09999999999999998 이다. 단지 반올림 함으로써 문제를 해결할 수 있다고 생각하지만, 항상 그렇게 할 수 있는 것은 아니다. 다음은 10 cent,20 cent,30 cent,..., 1 dollar까지 candy 값을 올려가며, 최..
무작위 정수 하나를 생성하는 문제가 심각한 코드 static Random rnd = new Random(); static int random(int n) { return Math.abs(rnd.nextInt()) % n; } // 무작위 수 100만개를 생성한 다음, 그중 중간 값보다 작은 게 몇 개인지를 출력하는 코드 public static void main(String[] args) { int n = 2 * (Integer.MAX_VALUE / 3); int low = 0; for (int i = 0; i < 1000000; i++) { if (random(n) < n / 2) low++; System.out.println(low); } } 위 코드에서는 3가지 문제가 있다. n이 그리 크지 않은 ..
for (Element e : elements) { ...// Do something with e } 위는 for each element e in elements 라고 읽힌다. foreach 문은 전통적인 for loop와 비교했을 때 성능차이가 없다. FOR EACH의 장점 // Can you spot the bug? enum Suit { CLUB, DIAMOND, HEART, SPADE } enum Rank { ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING } ... static Collection suits = Arrays.asList(Suit.values()); static Collection ranks..
지역변수의 유효 범위를 최소로 줄이면 코드 가독성과 유지보수성이 높아지고 오류 가능성은 낮아진다. 지역변수 초기화 자바에서는 문장을 선언할 수 있는 곳이면 어디서든 변수를 선언할 수 있다. 이렇기에 지역변수의 범위를 줄이는 가장 강력한 기법은 역시 가장 처음 쓰일 때 선언하기이다. 만약 사용하려면 멀었는데, 미리 선언부터 해두면 코드가 어수선해져 가독성이 떨어진다. 변수를 실제로 사용하는 시점엔 타입과 초깃값이 기억나지 않을 수도 있다. 그리고 지역변수를 생각 없이 선언하다 보면 변수가 쓰이는 범위보다 너무 앞서 선언하거나, 다 쓴 뒤에도 여전히 살아 있게 되기 쉽다. 또한 거의 모든 지역변수는 선언과 동시에 초기화해야 한다. 초기화에 필요한 정보가 충분하지 않다면 충분해질 때까지 선언을 미뤄야 한다. ..