컬렉션이 비었을 경우 null로 반환하면 될까? 런타임에 NullPointerException 예방하기 위해 클라이언트는 null 상황을 처리하는 코드를 추가로 작성해야한다. 컬렉션이나 배열같은 컨테이너가 비었을 때 null을 반환하는 메서드를 사용할 때면 항상 이와같은 방어 코드를 넣어줘야 한다. 때로는 빈 컨테이너를 할당하는데도 비용이 드니 null을 반환하는 쪽이 낫다는 주장도 있지만 이는 두가지 면에서 틀린 주장이다. 성능분석 결과 이 할당이 성능 저하의 주범이라고 확인되지 않는 한, 이 정도의 성능 차이는 신경 쓸 수준이 못 된다. 빈 컬렉션과 배열은 굳이 새로 할당하지 않고도 반환할 수 있다. 가능성은 작지만 사용 패턴에 따라 빈 컬렉션 할당이 성능을 눈에 띄게 떨어뜨릴 수 있다. 해법은 매번..
가변인수(varargs) 메서드는 명시한 타입의 인수를 0개 이상 받을 수 있다. 가변인수 메서드를 호출하면 가장먼저 인수의 개수와 길이가 같은 배열을 만들고 인수들을 이 배열에 저장하여 가변인수 메서드에 건네준다. 인수가 1개 이상어어야 하는 최솟값을 찾는 메서드라면 인수를 0개만 받을 수 있도록 설계하는 건 좋지 않다. 인수 개수는 런타임에 자동 생성된 배열의 길이로 알 수 있다. 이 방식의 심각한 문제는 인수를 0개만 넣어 호출하면 컴파일타임이 아닌 런타임에 실패한다는 점이다. 코드도 지저분하다. args 유효성 검사를 명시적으로 해야하고, min의 초깃값을 Integer.MAX_VALUE로 설정하지 않고는 더 명료한 for-each문도 사용할 수 없다.(가변인자에 값이 없을 수 있으니 무조건 초깃..
컬렉션을 집합, 리스트, 그 외로 구분하고자 Overroading을 적용한 프로그램 "집합", "리스트", "그 외"를 차례로 출력하는 프로그램을 예상했지만 실제 동작은 "그 외"만 연달아 출력한다. 오버로딩은 classify 메서드 중 어느 메서드를 호출할지 컴파일타임에 정해지기 때문이다. 컴파일타임에서 for 문안의 collection은 항상 Collection 타입이다. 런타임에는 타입이 매번 달라지지만, 호출할 메서드를 선택하는데는 영향을 주지 못한다. 따라서 컴파일타임의 매개변수 타입을 기준으로 항상 세번째 메서드인 classify(Collection)만 호출하는 것이다. 이처럼 직관과 어긋나는 이유는 재정의한 메서드는 동적으로 선택되고, 다중정의한 메서드는 정적으로 선택되기 때문이다. 메서드를..
메서드 이름을 신중히 짓자 항상 표준 명명 규칙을 따라야 한다. 이해할 수 있고 같은 패키지에 속한 다른 이름들과 일관되게 짓는게 최우선 목표다. 다음 목표는 개발자 커뮤니티에서 널리 받아들여지는 이름을 사용하는 것이다. 긴 이름은 피하자 애매하면 자바 라이브러리의 API 가이드를 참조하라. 자바 라이브러리가 워낙 방대하다 보니 일관되지 않은 이름도 제법 많지만 대부분 납득할 만 하다. 편의 메서드를 너무 많이 만들지 말자 모든 메서드는 각각 자신의 소임을 다해야 한다. 메서드가 너무 많은 클래스는 익히고, 사용하고, 문서화하고, 테스트하고, 유지보수하기 어렵다. 인터페이스도 마찬가지다. 메서드가 너무 많으면 이를 구현하는 사람과 사용하는 사람 모두 고통스럽게 한다. 클래스나 인터페이스는 자신의 각 기능..
자바는 안전한 언어다. 네이티브 메서드를 사용하지 않으니 C, C++ 같이 안전하지 않은 언어에서 흔히 보이는 버퍼오버런, 배열 오버런, 와일드 포인터 같은 메모리 충돌 오류에서 안전하다. 자바로 작성한 클래스는 시스템의 다른 부분에서 무슨 짓을 하든 그 불변식이 지켜진다. 메모리 전체를 하나의 거대한 배열로 다루는 언어에서는 누릴 수 없는 강점이다. 버퍼 오버플로(Buffer Overflow) 또는 버퍼 오버런(Buffer Overrun) 메모리를 다루는데 오류가 발생하여 잘못된 동작을 하는 프로그램 취약점 프로세스가 데이터를 버퍼에 저장할 때 프로그래머가 지정한 곳 바깥에 저장하는 것을 의미한다. 벗어난 데이터는 인접 메모리를 덮어 쓰게 되며 이 때 다른 데이터가 포함되어 있을 수도 있는데, 손상을 ..
메서드와 생성자에서 매개변수의 값이 인덱스로 사용될 때는 음수이면 사용할 수 없고 객체가 넘어올 경우 null이라면 참조하여 사용할 경우 NullPointerException이 나게된다. 이와 같이 매개변수 값이 특정 조건을 만족해야 하는 경우가 왕왕 있다. 이런 제약은 반드시 문서화해야하며 메서드 로직이 본격적으로 시작 되기 전에 검사되어야 한다. 이는 "오류는 가능한 빨리 발생한 곳에서 잡아야 한다"는 일반 원칙의 한 사례이기도 하다. 매개변수 검사를 제대로 하지 못하면 몇 가지 문제가 생길 수 있다. 메서드가 수행되는 중간에 모호한 예외를 던지며 실패할 수 있다. 더 나쁜 상황은 메서드가 잘 수행되지만 잘못된 결과를 반환할 때다. 한층 더 나쁜 상황은 메서드는 문제없이 수행됐지만, 어떤 객체를 이상..
자바 7까지 일련의 원소를 반환하는 메서드의 반환 타입 기본적으로 Collection 인터페이스 (Collection, List, Set...) for-each 문에서만 쓰이거나 일부 Collection을 구현할 수 없을때는 Iterable 인터페이스 반환된 원소들이 기본타입이거나 성능에 민감한 상황이라면 배열 자바 8이후 반복(iteration)을 지원하지 않는 Stream이 등장하며 반환 타입 선택이 복잡해졌다. 스트립과 반복을 알맞게 조합해야 좋은 코드가 나오는데 API를 스트림만 반환하도록 짜 놓으면 반환된 스트림을 for-each로 반복하길 원하는 사용자가 생겨날 수 있다. (Stream 인터페이스는 Iterable 인터페이스가 정의한 추상 메서드를 전부 포함할 뿐 아니라, Iterable 인터..
스트림 API 다량의 데이터 처리 작업(순차적이든 병렬적이든)을 돕고자 자바8에서 추가되었다. 이 API가 제공하는 추상 개념 중 핵심은 두가지다. 첫 번째인 스트림은 데이터 원소의 유한 혹은 무한 시퀀스를 뜻한다. 두번째인 스트림 파이프라인은 이 원소들로 수행하는 연산 단계를 표현하는 개념이다. 스트림 안의 데이터 원소들은 객체 참조나 기본 타입값이다. 기본 타입값으로는 int, long, double 이렇게 세가지를 지원한다. public static void main(String[] args) { List springClasses = new ArrayList(); springClasses.add(new OnlineClass(1, "spring boot", true)); springClasses.ad..