전체 글 194

[Effective Java] item 47. 반환 타입으로는 스트림보다 컬렉션이 낫다

[Effective Java] item 47. 반환 타입으로는 스트림보다 컬렉션이 낫다 핵심정리 원소 시퀀스를 반환하는 메서드를 작성할 때는, 이를 스트림으로 처리하기를 원하는 사용자와 반복으로 처리하길 원하는 사용자가 모두 있을 수 있음을 떠올리고, 양쪽을 다 만족시키려 노력하자. 컬렉션을 반환할 수 있으면 그렇게 하라. 반환 전부터 이미 원소들을 컬렉션에 담아 관리하고 있거나 컬렉션을 하나 더 만들어도 될 정도로 원소 개수가 적다면 ArrayList 같은 표준 컬렉션에 담아 반환하라. 그렇지 않으면 앞서의 멱집합 예처럼 전용 컬렉션을 구현할지 고민하라. 컬렉션을 반환하는 게 불가능하면 스트림과 Iterable 중 더 자연스러운 것을 반환하라. 만약 나중에 Stream 인터페이스가 Iterable을 지..

[Effective Java] item 46. 스트림에서는 부작용 없는 함수를 사용하라

[Effective Java] item 46. 스트림에서는 부작용 없는 함수를 사용하라 핵심정리 스트림 파이프라인 프로그래밍의 핵심은 부작용 없는 함수 객체에 있다. 스트림뿐만 아니라 스트림 관련 객체에 건네지는 모든 함수 객체가 부작용이 없어야 한다. 종단 연산 중 forEach는 스트림이 수행한 계산 결과를 보고할 때만 이용해야 한다. 계산 자체에는 이용하지 말자. 스트림을 올바로 사용하려면 수집기를 잘 알아둬야 한다. 가장 중요한 수집기 팩터리는 toList, toSet, toMap, groupingBy, joining이다. 스트림이 가져오는 함수형 프로그래밍의 패러다임 스트림은 그저 또 하나의 API가 아닌, 함수형 프로그래밍에 기초한 패러다임이다. 스트림이 제공하는 표현력, 속도 (상황에 따라서..

[Effective Java] item 45. 스트림은 주의해서 사용하라

[Effective Java] item 45. 스트림은 주의해서 사용하라 핵심 정리 스트림을 사용해야 멋지게 처리할 수 있는 일이 있고, 반복 방식이 더 알맞은 일도 있다. 그리고 수많은 작업이 이 둘을 조합했을 때 가장 멋지게 해결된다. 어느 쪽을 선택하든 확고부동한 규칙은 없지만 참고할 만한 지침 정도는 있다. 어느 쪽이 나은지가 확연히 드러나는 경우가 많겠지만, 아니더라도 방법은 있다. 스트림과 반복 중 어느 쪽이 나은지 확신하기 어렵다면 둘 다 해보고 더 나은 쪽을 선택하라. 스트림 스트림이란? 다량의 데이터 처리 작업(순차적이든 병렬적이든)을 돕고자 자바 8에 추가된 개념 스트림의 원소들은 어디로부터든 올 수 있다. 대표적으로는 컬렉션, 배열, 파일, 정규 표현식 패턴 매처(matcher), 난..

[Effective Java] item 44. 표준 함수형 인터페이스를 사용하라

[Effective Java] item 44. 표준 함수형 인터페이스를 사용하라 핵심정리 이제 자바도 람다를 지원하기 때문에 지금부터 API를 설계할 때 람다도 염두에 두어야 한다. 입력값과 반환값에 함수형 인터페이스 타입을 활용하라. 보통은 java.util.function 패키지의 표준 함수형 인터페이스를 사용하는 것이 가장 좋은 선택이다. 단 흔치는 않지만 직접 함수형 인터페이스를 만들어 쓰는 편이 나을 수도 있음을 잊지 말자. 불필요한 함수형 인터페이스를 만들지 말고 표준 함수형 인터페이스를 사용하라 자바가 람다를 지원하면서 API를 작성하는 모범 사례도 크게 바뀌었다. 예컨대 상위 클래스의 기본 메서드를 재정의해 원하는 동작을 구현하는 템플릿 매서드 패턴의 매력이 크게 줄었다. 이를 대체하는 현..

[Effective Java] item 43. 람다보다는 메서드 참조를 사용하라

[Effective Java] item 43. 람다보다는 메서드 참조를 사용하라 메서드 참조와 람다 람다가 익명 클래스보다 나은 점 중에서 가장 큰 특징은 간결함이다. 그런데 자바에서는 함수 객체를 심지어 람다보다도 더 간결하게 만드는 방법이 있으니, 바로 메서드 참조다. 다음 코드는 임의의 키와 Integer 값의 매핑을 관리하는 프로그램의 일부다. 이때 값이 키의 인스턴스 개수로 해석된다면, 이 프로그램은 멀티셋(multiset)을 구현한게 된다. 이 코드는 키가 맵안에 없다면 키와 숫자 1을 매핑하고, 이미 있다면 기존 매핑 값을 증가시킨다. map.merge(key, 1, (count, incr) -> count + incr); 이 코드는 자바 8때 Map에 추가된 marge 메서드를 사용했다. ..

[Effective Java] item 42. 익명 클래스보다는 람다를 사용하라

[Effective Java] item 42. 익명 클래스보다는 람다를 사용하라 과거에 익명 클래스를 사용하던 방식 예전에는 자바에서 함수 타입을 표현할 때 추상 메서드를 하나만 담은 인터페이스(드물게는 추상 클래스)를 사용했다. 이런 인터페이스의 인스턴스를 함수 객체라고 하여, 특정 함수나 동작을 나타내는 데 썼다. 1997년 JDK 1.1이 등장하면서 함수 객체를 만드는 주요 수단은 익명 클래스(아이템 24)가 되었다. 다음 코드를 예로 살펴보자. 문자열을 길이순으로 정렬하는데, 정렬을 위한 비교함수로 익명 클래스를 사용한다. 익명 클래스의 인스턴스를 함수 객체로 사용 - 낡은 기법이다! Collections.sort(words, new Comparator()){ public int compare(S..

[Effective Java] item 41. 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라

[Effective Java] item 41. 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라 핵심 정리 마커 인터페이스와 마커 애너테이션은 각자의 쓰임이 있다. 마커 인터페이스 새로 추가하는 메서드가 없이 단지 타입 정의가 목적일 경우 마커 애너테이션 클래스나 인터페이스 외의 프로그램 요소에 마킹해야 하거나, 애너테이션을 적극 활용하는 프레임워크의 일부로 그 마커를 편입시키고자 할 경우 적용 대상이 ElementType.TYPE인 마커 애너테이션을 작성하고 있다면, 잠시 여유를 갖고 정말 애너테이션으로 구현하는 것이 옳은지, 혹은 마커 인터페이스가 낫지 않을지 곰곰이 생각해보자. 마커 인터페이스 아무 메서드도 담고 있지 않고, 단지 자신을 구현하는 클래스가 특정 속성을 가짐을 표시해주는 인터페이스..

[Effective Java] item 40. @Override 애너테이션을 일관되게 사용하라

[Effective Java] item 40. @Override 애너테이션을 일관되게 사용하라 핵심 정리 재정의한 모든 메서드에 @Override 애너테이션을 의식적으로 달면 여러분이 실수했을 때 컴파일러가 바로 알려줄 것이다. 예외는 한 가지 뿐이다. 구체 클래스에서 상위 클래스의 추상 메서드를 재정의한 경우엔 이 애너테이션을 달지 않아도 된다. (단다고 해서 해로울 것도 없다.) @Override 애너테이션 자바가 기본적으로 제공하는 애너테이션 중 보통의 프로그래머에게 가장 중요한 것은 @Override일 것이다. @Override는 메서드 선언에만 달 수 있으며, 이 애너테이션이 달렸다는 것은 상위 타입의 메서드를 재정의했음을 뜻한다. 이 애너테이션을 일관되게 사용하면 여러 가지 악명 높은 버그들을..

[Effective Java] item 39. 명명 패턴보다 애너테이션을 사용하라

[Effective Java] item 39. 명명 패턴보다 애너테이션을 사용하라 명명 패턴 도구나 프레임워크가 특별히 다루어야 할 프로그램 요소에 구분되는 명명 패턴을 적용하는 것. 예를 들어 Junit 3까지는 테스트 메서드 이름을 test로 시작해야만 했다. 명명 패턴의 단점 1. 오타가 나면 안된다. Junit 3까지의 테스트 메서드 이름이 고정되어 있어서, 오타로 tsetSafetyOverride로 지으면 이 메서드를 무시하고 지나쳐서 테스트가 통과되었다고 오해할 수 있다.2. 올바른 프로그램 요소에만 사용되리라 보증할 방법이 없다. 클래스 이름을 TestSafetyMechanism으로 지어 Junit에 던졌을 때, 개발자는 이 테스트가 수행되길 기대하겠지만 Junit은 경고 메세지조차 출력하지..

[Effective Java] item 38. 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라

[Effective Java] item 38. 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라 핵심 정리 열거타입 자체는 확장할 수 없지만, 인터페이스와 그 인터페이스를 구현하는 기본 열거 타입을 함께 사용해 같은 효과를 낼 수 있다. 이를 통해 클라이언트는 이 인터페이스를 구현해 자신만의 열거 타입(혹은 다른 타입)을 만들 수 있다. API가 (기본 열거 타입을 직접 명시하지 않고) 인터페이스 기반으로 작성되었다면 기본 열거 타입의 인스턴스가 쓰이는 모든 곳을 새로 확장한 열거 타입의 인스턴스로 대체해 사용할 수 있다. 타입 안전 열거 타입 public final class Direction { public static final Direction NORTH = new Direction("N..