지역변수의 유효범위 지역 변수의 유효 범위를 최소로 줄이면 코드 가득성과 유지보수성이 높아지고 오류 가능성은 낮아진다. 자바에서는 문장을 선언할 수 있는 어느 곳이면 어디서든 변수를 선언할 수 있다. 지역변수의 범위를 줄이는 가장 강력한 방법은 '가장 처음 쓰일때 선언하기'다. 미리 선언부터 해두면 코드가 어수선해진다. 변수를 실제로 사용하는 시점엔 타입과 초깃값이 기억나지 않을 수도 있다. 지역변수의 범위는 선언된 지점부터 그 지점을 포함한 블록이 끝날 때 까지다. package com.java.effective.item57; public class Main { public static void main(String[] args) { int test = 1; /* 블록이 끝날때까지 유효 */ } } 거..
Javadoc 자바독 16가지 설명 자바독은 소스코드 파일에서 문서화 주석(doc comment; 자바독 주석)이라는 특수한 형태로 기술된 설명을 추려 API 문서로 변환해준다. 문서화 주석을 작성하는 규칙은 공식 언어 명세에 속하진 않지만 자바 프로그래머라면 알아야하는 업계 표준 API다. 아래의 유의점을 보자. 1) 개발한 API를 올바르게 문서화하려면 공개된 모든 클래스, 인터페이스, 메서드, 필드 선언에 문서화 주석을 달아야한다. 직렬화할 수 있는 클래스라면 적렬화 형태에 관해서도 적어야한다. 문서화 주석이 없다면 자바독도 그저 공개 API 요소들의 '선언'만 나열해주는 게 전부다. 문서가 잘 갖춰지지않은 API는 쓰기 헷갈려서 오류의 원인이 되기 쉽다. 2) 메서드용 문서화 주석에는 해당 메서드..
빈 값 처리방법 Optioanl 자바 8 전에는 메서드가 특정 조건에서 값을 반환할 수 없을때 취할 수 있는 선택지는 두가지였다. 1) 예외를 던진다. 2) null 을 반환한다. (반환 타입이 객체 참조일 경우) 두 가지 방법 모두 허점이 있다. 예외는 진짜 예외적인 상황에서 사용해야한다. null을 반환하면 클라이언트에서 별도의 null 처리 코드를 추가해야한다. 자바 8 후에 한가지 방법이 생겼다. 3) Optional 로 처리한다. 3)번의 방법은 null 이 아닌 T 타입 참조를 하나 담거나, 혹은 아무것도 담지 않을 수 있다. 아무것도 담지 않은 옵셔널은 '비었다'라고 말한다. Optional은 원소를 최대 1개 가질 수 있는 '불변' 컬렉션이다. Optional 가 Collection를 구현..
null 처리 package com.java.effective.item54; import java.util.ArrayList; import java.util.List; public class Main { private final static List cheesesInStock = new ArrayList(); /** * 재고가 없다면 null 반환 * @return */ public static List getCheeses() { return cheesesInStock.isEmpty() ? null : new ArrayList(cheesesInStock); } public static void main(String[] args) { } enum Cheese { STILTON } } 재고가 없다면 null..
가변인수 메서드 가변인수(varags) 메서드는 명시한 타입의 인수를 0개 이상 받을 수 있다. * 가변 인수 메서드 호출 과정 1) 먼저 인수의 개수와 길이가 같은 배열을 만든다. 2) 만들어진 인수들을 이 배열에 저장한다. 3) 배열을 가변 인수 메서드에 건네준다. 가변인수 예제코드 package com.java.effective.item53; import java.util.Arrays; public class Main { public static void main(String[] args) { System.out.println(sum(1, 2, 3)); } static int sum(int... args) { return Arrays.stream(args).sum(); } } 인수가 1개 이상이어야..
다중정의 package com.java.effective.item52; import java.math.BigInteger; import java.util.*; 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) { Collection[] collections = { new HashSet(), new ArrayList(..
메서드 시그니처 설계 1) 메서드 이름을 신중히 짓자. 항상 표준 명명 규칙을 따라야한다. 이해할 수 있고, 같은 패키지에 속한 다른 이름들과 일관되게 짓는게 최우선 목표다. 긴 이름은 피하고, 애매하면 자바 라이브러리의 API 가이드를 참조하자. 2) 편의 메서드를 너무 많이 만들지 말자. 모든 메서드는 각자 자신의 소임을 다해야한다. 메서드가 너무 많은 클래스는 익히고, 사용하고, 문서화하고, 테스트하고, 유지보수하기 어렵다. 클래스나 인터페이스는 자신의 각 기능을 완벽히 수행하는 메서드로 제공해야한다. 3) 매개변수 목록은 짧게 유지하자. 매개변수가 4개 이상 넘어가면 이를 기억하기가 쉽지 않다. 같은 타입의 애개변수 여러개가 연달아 나오는 경우는 더 해롭다. 사용자가 매개변수 순서를 기억하기 어려..
불변식 깨뜨리기 자바는 메모리 충돌 오류에서 안전한 언어다. 자바로 작성한 클래스는 시스템의 다른 부분에서 무슨 짓을 하든 그 불변식이 지켜진다. 하지만 아무리 자바라고 해도 다른 클래스로부터의 침범을 아무런 노력없이 다 막을 수 있는건 아니므로 방어적으로 프로그래밍해야 한다. 어떤 객체든 그 객체의 허락 없이는 외부에서 내부를 수정하는 일은 불가능하다. 하지만 실수로 내부를 수정하도록 허락하는 경우가 생긴다. Period.java package com.java.effective.item50; import java.util.Date; public class Period { private final Date start; private final Date end; public Period(Date start..
메서드 매개변수 검사 메서드와 생성자 대부분은 입력 매개변수의 값에 제약이 있다. 예를 들어, 음수이면 안되고, 객체 참조는 null이 아니여야한다는 식이다. 이런 제약은 반드시 문서화해야 하며, 메서드 몸체가 시작되기 전에 검사해야한다. 이는 "오류는 가능한 한 빨리 잡아야 한다"는 일반 원칙의 한 사례다. 오류를 발생한 즉시 잡지 못하면 해당 오류를 감지하기 어려워지고, 감지하더라도 오류의 발생 지점을 찾기 어려워진다. 메서드 몸체가 실행되기 전에 매개변수를 확인한다면 잘못된 값이 넘어왔을때 즉각적이고 깔끔한 방식으로 예외를 던질 수 있다. 매개변수 검사를 제대로 하지 못하면 몇가지 문제가 생길 수 있다. 1) 메서드가 수행되는 중간에 모호한 예외를 던지며 실패할 수 있다. 2) 메서드가 잘못된 결과..
파이프라인 병렬 실행 자바 8부터는 parallel 메서드만 한번 호출하면 파이프라인을 병렬 실행할 수 있는 스트림을 지원했다. 이를 올바르고 빠르게 작성하는 일은 여전히 어려운 작업이다. 동시성 프로그래밍을 할때는 안정성과 응답가능 상태를 유지하기 위해 애써야한다. 메르센 소수를 생성하는 프로그램 package com.java.effective.item48; import java.math.BigInteger; import java.util.stream.Stream; import static java.math.BigInteger.ONE; import static java.math.BigInteger.TWO; /** * 메르센 소수를 생성하는 코드 */ public class Main { public st..
스트림 반환타입 스트림은 for-each 반복을 제공하지 않는다. API를 스트림만 반환하도록 짜놓으면 반환된 스트림을 for-each로 반복하길 원하는 사용자는 불편하다. Stream 인터페이스는 Iterable 인터페이스가 정의한 추상 메서드를 전부 포함하고, Iterable 인터페이스가 정의한 방식대로 동작한다. 그럼에도 for-each로 스트림을 반복할 수 없는 까닭은 Stream이 Iterable을 확장하지 않아서다. Iterator List list = List.of(1,2,3); Iterator iterator = list.iterator(); while(iterator.hasNext()) { system.out.println(iterator.next()); } 스트림의 경우에는 내부에 It..
스트림 패러다임 스트림은 그저 또 하나의 API 가 아닌, 함수형 프로그래밍에 기초한 패러다임이다. 스트림이 제공하는 표현력, 속도, 병렬성을 얻으려면 API는 말할것도 없고 이 패러다임까지 함께 받아들여야 한다. 스트림 패러다임의 핵심은 일련의 변환 (transformation)으로 재구성하는 부분이다. 이때 각 변환 단계는 가능한 한 이전 단계의 결과를 받아 처리하는 순수 함수여야 한다. * 순수함수 오직 입력만이 결과에 영향을 주는 함수로, 다른 가변 상태를 참조하지 않고, 함수 스스로도 다른 상태를 변경하지 않는다. 스트림에서는 순수함수여야 하기 때문에 스트림 연산에 건네는 함수 객체에 모두 부작용이 없어야한다. 예제 텍스트 파일에서 단어별 수를 세어 빈도표를 만드는 예제 스트림 패러다임을 이해하..