핵심 정리 이미 잘 만들어 놓은 라이브러리를 잘 활용하자. 표준 라이브러리 사용 예제 : Random // 직접 구현 static Random rnd = new Random(); static int random(int n) { return Math.abs(rnd.nextInt()) % n; } 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); } 위 코드는 세 가지 문제점을 지니고 있다. n이 그리 크지 않은 2의 제곱수라면 얼마 지나지 않아..
핵심 정리 가능한 모든 곳에서 for문이 아닌 for-each문을 사용하자. for문 vs for-each문 // 컬렉션 순회하기 - 더 나은 방법이 있다. for (Iterator i = c.iterator(); i.hasNext(); ){ Element e = i.next(); ... //e로 무언가를 한다. } // 배열 순회하기 - 더 나은 방법이 있다. for (int i = 0; i < a.length; i++) { ..// a[i]로 무언가를 한다. 위 방법은 while 문보다는 낫지만(item 57) 그렇다고 가장 좋은 방법은 아니다. 이유는 다음과 같다. 반복자와 인덱스 변수는 코드만 지저분하게 할 뿐 필요한 것은 원소들 뿐이다. 반복자와 인덱스 변수를 잘못 사용할 가능성이 높아진다. 컬..
지역변수의 범위를 최소화하라. : 코드 가독성과 유지보수성이 높아지고 오류 가능성이 낮아진다. 클래스의 멤버와 접근 권한을 최소화하라(item 15)와 비슷한 의도이다. 이번 포스트에서는 지역변수의 범위를 최소화하는 방법에 대해 다룬다. 가장 처음 사용되는 시점에서 선언하자. 코드의 어수선함을 줄이고 가독성을 높일 수 있다. 변수가 미리 선언되어 있으면 그 타입이나 초기값을 찾기 어려울 수 있다. 선언과 동시에 초기화하자. 필요한 정보가 충분하지 않다면 선언을 늦추는 것이 좋다. try-catch 문은 이 규칙에서 예외다. 변수를 초기화하는 표현식에서 검사 예외를 던질 가능성이 있다면 try 블록 안에서 초기화해야 한다. BufferedReader reader; try { reader = new Buff..
자바독(Javadoc) 소스코드 파일에서 자바독 주석이라는 특수한 형태로 기술된 설명을 API 문서로 변환해준다. Java 언어로 작성된 소스 코드에 대한 문서를 HTML 형식으로 생성하는 도구이다. 클래스, 인터페이스, 메소드, 필드 등에 대한 설명을 제공한다. 공개된 모든 클래스, 인터페이스, 메소드, 필드 선언에 문서화 주석을 달아야 한다. 직렬화할 수 있는 클래스라면 직렬화 형태(item 87)에 관해서도 작성해야 한다. 자바의 기본 생성자에는 문서화 주석을 작성할 수 없다. 따라서 공개 클래스는 절대 기본 생성자를 사용하면 안 된다. 유지 보수를 위해 비공개 클래스, 인터페이스, 생성자, 메소드, 필드에도 문서화 주석을 달아야 한다. 메소드용 문서화 주석에는 해당 메소드와 클라이언트 사이의 규약..
핵심 정리 값을 반환하지 못할 가능성이 있는 메소드라면 옵셔널을 반환하는 것을 고려해보자. 그러나 옵셔널 반환에는 성능 저하가 따를 수 있으니, 성능에 민감한 경우 null을 반환하거나 예외를 던지는 것이 나을 수 있다. 또한, 옵셔널을 반환값 이외의 용도로 쓰는 경우는 매우 드물다. 메소드가 특정 조건에서 값을 반환할 수 없을 때 : 자바 8 이전 방법 1 : 예외 처리 👉 좋지 않은 방법 예외는 정말 예외적인 상황에서만 사용해야 한다.(item 69) 메소드의 정상적인 동작 흐름을 중단시킨다. 스택 추적을 생성하므로 성능 측면에서 비용이 발생한다. 방법 2 : 반환 타입이 객체 참조라면, null 반환 👉 좋지 않은 방법 null 체크를 해야 하는 코드를 추가적으로 작성해야 한다. 괴로운 NullPo..
핵심 정리 null이 아닌 빈 배열이나 컬렉션을 반환하라. 성능적으로도 좋고 오류 처리 코드도 필요 없다. null을 반환하는 메소드 // 잘못된 예 private final List cheesesInStock = ...; /** * @return 매장 안의 모든 치즈 목록을 반환한다. * 단, 재고가 하나도 없다면 null을 반환한다. */ public List getCheeses() { return cheesesInStock.isEmpty() ? null : new ArrayList(cheesesInStock); } 위 코드는 NullPointerException을 발생시키는 경우가 많으며, 이에 따라 디버깅이 어렵게 된다. // 방어 코드 List cheeses = shop.getCheeses();..
핵심 정리 가변인수는 필요에 따라 개수가 달라질 수 있는 인수를 메소드에 넘길 때 유용하다. 그러나 메소드가 호출될 때마다 배열을 새로 할당하고 초기화하는 비용이 발생한다. 따라서 성능에 민감한 상황에서는 메소드 오버로딩을 통해 성능을 최적화하도록 하자. 가변인수 예시 : int 인수들의 합을 계산해주는 가변인수 메소드 간단한 가변인수 활용 예 static int sum(int... args) { int sum = 0; for (int arg : args) sum += arg; return sum; } 인수가 1개 이상이어야 하는 가변인수 메소드 - 잘못 구현한 예 public static int min(int... args) { if (args.length == 0) { throw new Illegal..
핵심 요약 매개변수 수가 같을 경우 오버로딩을 피하자. 그러나 구현해야 할 경우, 형변환을 통해 명확히 선택하도록 하자. 그것이 불가능하다면 같은 객체을 입력받는 오버로딩 메소드들에 대해 모두 동일하게 동작하도록 하자. 재정의(Overriding)와 다중정의(Overloading) : 재정의한 메소드는 동적으로, 다중정의한 메소드는 정적으로 선택된다. 재정의(Overriding) 메소드를 재정의한 다음 하위 클래스 인스턴스에서 메소드를 호출하면 재정의한 메소드가 실행되며, 컴파일 타임의 인스턴스 타입은 신경쓰지 않는다. class Wine { String name() { return "포도주"; } } class SparklingWine extends Wine { @Override String name(..