Java 생태계에는 java.io, java.lang, java.util 등 자바 표준 라이브러리나 고품질의 서드파티 라이브러리 등 수많은 라이브러리들이 존재한다. 아주 특별한 나만의 기능이 아니라면 이미 누군가가 라이브러리 형태로 구현해놓았을 가능성이 크다. 이러한 라이브러리들은 일반적으로 코드의 품질이 좋고 지속해서 개선된다. 구현해야 할 기능이 라이브러리로 존재한다면 그것을 사용하자. 있는지 잘 모르겠다면 찾아보자. 우리는 그 라이브러리가 어떤 영역의 기능을 제공하는지 살펴보고, 익히고, 사용하면 된다. 표준 라이브러리를 잘 활용하지 못한 예제 아주 흔히 마주치는 문제로, 다음과 같은 메서드를 만들곤 한다. // 문제가 많은 코드! static Random rnd = new Random(); sta..
가능한 모든 곳에서 전통적인 for 문보다는 for-each 문을 사용하는 것이 좋다. 전통적인 for 문과 비교했을 때 for-each문은 명확하고, 유연할 뿐 아니라 버그를 예방해주는 효과가 있다. 또 성능 저하도 없다. // 전통적인 for 문 - 컬렉션 순회 for(Iterator i = c.iterator(); i.hasNext();) { Element e = i.next(); } // 전통적인 for 문 - 배열 순회 for (int i = 0; i < a.length; i++) { int z = a[i]; // a[i]로 무언가를 한다. } 전통적인 for 문은 while문 보다는 낫지만 가장 좋은 방법은 아니다. 우리에게 필요한 건 원소뿐인데 for 문 안의 반복자와 인덱스가 코드를 지저분..
클래스와 멤버의 접근 권한을 최소화하면 얻을 수 있는 이점이 많듯, 지역변수의 유효 범위를 최소로 줄이면 코드 가동성과 유지보수성을 높일 수 있고 오류 가능성을 낮출 수 있다. 지역변수 범위 최소화하기 1. 가장 처음 쓰일 때 선언하기 가장 강력한 기법은 역시 '가장 처음 쓰일 때 선언하기'이다. 변수를 미리 선언해두면 코드가 어수선해지고 가독성이 떨어진다. 또한, 의도한 범위 외에서 그 변수를 사용하면 오류 가능성이 높아진다. 2. 선언과 동시에 초기화 초기화에 필요한 정보가 충분하지 않다면 충분해질 때까지 선언을 미뤄야 한다. 단, try-catch 구문에서의 이 규칙은 예외이다. 3. 메서드를 작게 유지하고 한 가지 기능에 집중하기 하나의 메서드가 여러가지 역할을 가지는 경우 그중 한 기능과만 관련..
API를 쓸모 있게 하려면 잘 작성된 문서도 함께 제공해야 한다. 자바에서는 자바독이라는 유틸리티가 이 작업을 도와준다. 문서화 주석을 작성하는 규칙은 공식 언어 명세에 속하진 않지만 자바 프로그래머라면 응당 알아야 하는 업계 표준 API라 할 수 있다. API를 올바르게 문서화하는 방법 API를 올바로 문서화하려면 공개된 모든 클래스, 인터페이스, 메서드, 필드 선언에 문서화 주석을 달아야 한다. 직렬화할 수 있는 클래스라면 직렬화 형태에 대해서도 적어야 한다, 문서가 잘 갖춰지지 않은 API는 쓰기 헷갈려서 오류의 원인이 되기 쉽다. 꼭 문서화를 하자. 기본 생성자에는 문서화 주석을 달 수 없으니 공개 클래스는 절대 기본 생성자를 사용하지 말자. 유지보수를 고려한다면 대다수의 공개되지 않은 클래스, ..
Java8 이전에는 메서드가 특정 조건에서 값을 반환할 수 없을 때 예외를 던지거나, null을 반환하는 두 가지 방법이 있었다. 그런데 Java8로 버전이 올라가면서 Optional라는 또 하나의 선택지가 생겼다. Java8 이전, 메서드가 특정 조건에 값을 반환할 수 없을 때 처리 방법에는 예외를 던지거나 null을 반환하는 두 가지의 선택지가 존재한다. 하지만 이 방법들에는 모두 단점이 존재한다. 1. 예외를 던진다. 예외는 진짜 예외적인 상황에서만 사용해야 한다. 예외를 생성할 때 스택 추적 전체를 캡처하는 비용이 만만치 않다. 2. null을 반환한다. 별도의 null 처리 코드를 추가해야 한다. null 처리를 무시하고 저장해두면 언젠가 NullPointerException이 발생할 가능성이 ..
컬렉션이나 배열 같은 컨테이너가 비었을 때 null을 반환하는 메서드를 사용할 때면 항상 방어 코드를 넣어줘야 한다. 다음 예제를 살펴보자. private final List cheesesInStock = ...; /** * @return 매장 안의 모든 치즈가 목록을 반환한다. * 단, 재고가 없다면 null을 반환한다. */ public List getCheeses() { return cheesesInStock.isEmpty() ? null : new ArrayList(cheesesInStock); } 클라이언트 코드에서 null 체크 코드를 추가적으로 작성해야 한다. 이 방어 코드를 빼먹으면 오류가 발생할 수 있기 때문에 항상 명시해줘야 하므로 코드가 더 복잡해진다. 빈 컨테이너를 할당하는 것에도 ..
인수 개수가 일정하지 않은 메서드를 정의해야 한다면, 가변인수가 반드시 필요하다. 하지만 가변인수는 신중하게 사용해야 한다. 인수가 1개 이상이어야 하는 가변인수 메서드에서 인수를 0개 받을 수 있도록 설계하는 것은 좋지 않다. 인수 개수는 런타임에 배열의 길이로 알 수 있기 때문이다. 즉, 런타임에 실패할 수 있다는 뜻이다. 예를 들어, 최솟값을 찾는 가변인수 메서드가 있다고 생각해보자. // 인수 1개 이상어야하는 최솟값을 찾는 가변인수 메서드 - 잘못 구현한 예제 static int min(int... args) { if (args.length == 0) throw new IllegalArgumentException("인수가 1개 이상 필요합니다."); int min = args[0]; for (i..
이름이 같은 메서드가 매개변수의 타입이나 개수만 다르게 갖는 형태를 다중정의(overloading)라고 한다. 이 다중 정의를 사용할 때는 신중해야 한다. 다중정의(Overloading) 다음과 같이 컬렉션을 구분하기 위한 프로그램이 있다고 생각해보자. public class CollectionClassifier { public static String classify(Set s) { return "집합"; } public static String classify(List lst) { return "리스트"; } public static String classify(Collection c) { return "그 외"; } public static void main(String[] args) { Colle..
API 설계 요령을 잘 활용하면 배우기 쉽고, 쓰기 쉬우며, 오류 가능성이 적은 API를 만들 수 있다. 5가지 API 설계 요령 1. 메서드의 이름을 신중히 짓자 표준 명명 규칙에 따라 메서드 이름을 짓는다. 메서드 명은 같은 패키지에 속한 다른 이름들과 일관되게 짓는다. 개발자 커뮤니티에서 널리 받아들여지는 이름을 사용하자. 너무 긴 메서드 명은 피하자. 애매하다면 자바 API 가이드를 참조해 이름을 지어보자. 2. 편의 메서드를 너무 많이 만들지 말자 너무 많은 메서드를 가진 클래스나 인터페이스는 사용하고, 문서화하고, 테스트하고, 유지 보수하기 어렵다. 또한, 구현하는 사람과 사용하는 사람 모두를 고통스럽게 한다. 클래스나 인터페이스는 자신의 각 기능을 완벽히 수행하는 메서드로 제공해야 하며, 아..