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. 편의 메서드를 너무 많이 만들지 말자 너무 많은 메서드를 가진 클래스나 인터페이스는 사용하고, 문서화하고, 테스트하고, 유지 보수하기 어렵다. 또한, 구현하는 사람과 사용하는 사람 모두를 고통스럽게 한다. 클래스나 인터페이스는 자신의 각 기능을 완벽히 수행하는 메서드로 제공해야 하며, 아..
자바는 안전한 언어다. C, C++같은 언어에서 흔히 보이는 메모리 충돌 오류에서 안전하고, 자바로 작성한 클래스는 시스템의 다른 부분에서 무슨 짓을 하든 불변식이 지켜지기 때문이다. 하지만 자바라도 다른 클랜스로부터의 침범을 다 막을 수 있는 건 아니다. 따라서 누군가 불변식을 깨뜨리려 한다는 가정하에 방어적으로 프로그래밍을 해야한다. 외부에서 내부를 수정할 수 있는 경우 보통 객체의 허락 없이는 외부에서 내부를 수정하는 일은 불가능하다. 하지만 의도치 않게 외부에서 내부를 수정하도록 허락하는 상황이 생길 수 있다. 다음과 같이 기간(Period)을 표현하는 클래스 있다. 개발자는 Period 값이 한번 정해지면 변하지 않게 할 의도로 만들었다고 가정해보자. public final class Perio..
오류는 가능한 한 빨리 발생한 곳에서 잡아야 한다. 오류를 발생한 즉시 잡지 못하면 해당 오류를 감지하기 어려워지고, 오류 발생 지점을 찾기 어려워진다. 메서드의 매개변수 또한 마찬가지이다. 메서드 몸체가 실행되기 전에 매개변수를 확인한다면 잘못된 값이 넘어왔을 때 깔끔한 방식으로 예외를 던질 수 있다. 매개변수 검사를 제대로 하지 못하면 발생하는 문제 1. 메서드가 수행 중간에 모호한 예외를 던지며 실패할 수 있다. 2. 메서드가 잘 수행되지만 잘못된 결과를 반환할 수 있다. 3. 메서드는 문제없이 수행됐지만, 미래의 알 수 없는 시점에 메서드와 관련 없는 오류를 낼 수 있다. (실패 원자성을 어기는 상황) public과 protected 메서드는 예외를 문서화하자 @throws 자바독 태그를 사용해 ..
Java8부터는 parallel 메서드만 호출하면 파이프라인을 병렬 실행할 수 있는 스트림을 지원한다. 동시성 프로그램을 작성하기는 쉬워지고 있지만, 올바르고 빠르게 작성하는 일은 여전히 어려운 일이다. 동시성 프로그래밍을 할 때는 안전성과 응답 가능 상태를 유지해야 한다. 병렬 스트림 파이프라인 프로그래밍에서도 다를 바 없다. 파이프라인 병렬화로 성능 개선을 기대하기 어려운 경우 // 스트림을 사용해 처음 20개의 메르센 소수를 생성하는 프로그램 public class MersennePrime { public static void main(String[] args) { primes().map(p -> TWO.pow(p.intValueExact()).subtract(ONE)) //.parallel() ...