Effective Java
  • 들어가기전 스트림의 기본 개념은 숙지해야한다. 스트림 기본개념 포스팅 바로가기 https://devfunny.tistory.com/341 스트림의 기본개념 도입 모든 자바 애플리케이션은 컬렉션을 만들고 처리하는 과정을 포함한다. 컬렉션은 대부분의 프로그래밍 작업에 사용될 정도로 어디서든 사용되어지고있다. 하지만 컬렉션을 많이 사용함에 devfunny.tistory.com 스트림 스트림 API는 다량의 데이터 처리 작업을 위해 추가되었다. 이 API가 제공하는 추상 개념 중 핵심은 두가지다. 1) 스트림은 데이터 원소의 유한 혹은 무한 시퀀스를 뜻한다. 2) 스트림 파이프라인(stream pipeline)은 이 원소들로 수행하는 연산 단계를 표현하는 개념이다. 스트림의 파이프 라인은 소스 스트림에서 시작하..

    Read more
  • 함수형 매개변수 타입 자바가 람다를 지원하면서 템플릿 메서드 패턴의 매력이 크게 줄었다. * 템플릿 메서드 패턴 상위 클래스의 기본 메서드를 재정의해 원하는 동작을 구현하는 디자인패턴 이를 대체하는 현대적인 해법은 같은 효과의 함수 객체를 받는 정적 팩터리나 생성자를 제공하는 것이다. 이때 함수형 매개변수 타입을 올바르게 선택해야한다. LinkedHashMap 의 protect 메서드인 removeEldestEntry 를 재정의하면 캐시로 사용할 수 있다. 맵에 새로운 키를 추가하는 put 메서드는 이 메서드를 호출하여 true가 반환되면 맵에서 가장 오래된 원소를 제거한다. LinkedHashMap의 removeEldestEntry() ... /** * Sample use: this override w..

    Read more
  • 메서드 참조 자바 8부터 등장한 람다는 익명 클래스보다 간결하다. 자바에는 함수 객체를 람다보다도 더 간결하게 만드는 방법이 있는데, 바로 메서드 참조(method reference) 다. map.merge(key, 1, (count, incr) -> count + incr); 이때 값이 키의 인스턴스 개수로 해석된다면 이 프로그램은 멀티셋(multiset)을 구현한게 된다. 1) key 가 없을 경우 : 1 2) key 가 있을 경우 : 기존 매핑값을 증가 Map.java 의 merge() default V merge(K key, V value, BiFunction

    Read more
  • 익명클래스 익명 클래스란, 함수 객체를 만드는 주요 수단이다. 함수 객체란, 자바에서 함수 타입을 표현할때 추상 메서드를 1개만 담은 인터페이스를 사용했는데, 이런 인터페이스의 인스턴스를 말한다. 특정 함수나 동작을 나타나는데 사용되었다. public static void main(String[] args) { Collections.sort(List.of("aa", "bbb", "ccc", "dddd"), new Comparator() { @Override public int compare(String o1, String o2) { return Integer.compare(o1.length(), o2.length()); } }); } 람다식 전략 패턴처럼, 함수 객체를 사용하는 과거 객체 지향 디자인 패..

    Read more
  • 마커 인터페이스 아무 메서드도 담고 있지 않고, 단지 자신을 구현하는 클래스가 특정 속성을 가짐을 표시해주는 인터페이스이다. Serializable 인터페이스가 좋은 예다. Serializable.java package java.io; public interface Serializable { } Serializable은 자신을 구현한 클래스의 인스턴스를 ObjectOutputStream 을 통해 write할 수 있다고, 즉 직렬화(serialization)할 수 있다고 알려준다. 마커 어노테이션 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface marker { } 마커 인터페이스의 장점 마커 애노테이션이 등장하면..

    Read more
  • @Override 애노테이션 자바가 기본으로 제공하는 애노테이션 중 보통의 프로그래머에게 가장 중요한 것은 @Override 일 것이다. @Override 는 메서드 선언에만 달 수 있고, 이는 상위 타입의 메서드를 재정의했음을 뜻한다. 이 애노테이션을 일관되게 사용해야한다. 예시 영어 알파벳 2개로 구성된 문자열을 표현하는 Bigram 프로그램을 살펴보자. Bigram.java package com.java.effective.item40; import java.util.HashSet; import java.util.Set; public class Bigram { private final char first; private final char second; public Bigram(char first, ..

    Read more
  • 명명패턴의 단점 1. JUnit3까지 테스트 메서드 이름은 testxx로 시작해야했다. 만일 오타가 발생하여 tsetxx로 메서드명을 지정한다면, 이 메서드는 무시되어 테스트가 통과되었다고 오해할 수 있다. 2. 올바른 프로그램 요소에서만 사용되리라는 보증할 방법이 없다. JUnit3 이하에서 클래스 이름을 Testxx로로 던져줬다고 해보자. 개발자는 이 클래스에 정의된 테스트 메서드들을 수행해주길 기대하겠지만 JUnit은 클래스 이름에는 관심이 없다. 3. 프로그램 요소를 매개변수로 전달할 마땅한 방법이 없다. 특정 예외를 던져야만 성공하는 테스트가 있을 때, 기대하는 예외 타입을 테스트에 매개변수로 전달해야한다. 예외의 이름을 테스트 메서드 이름에 덧붙이는 방법도 있지만 이는 보기도 나쁘고 깨지기도 ..

    Read more
  • 열거타입 구현체 열거 타입은 확장이 불가능하다. 열거 타입을 확장하는 건 좋지 않은 생각이며, 확장성을 높일 경우 고려햘 요소가 늘어나 설계와 구현이 더 복잡해진다. 그런데 확장할 수 있는 열거타입이 어울리는 쓰임이 최소한 하나는 있다. 바로 연산 코드다. 연산 코드의 각 원소는 특정 기계가 수행하는 연산을 뜻하고, 연산을 확장할 경우 추가할 수 있도록 열어줘야한다. 열거 타입으로 확장하는 효과를 내보자. 임의의 인터페이스를 구현하면 된다. 열거 타입이 그 인터페이스의 구현체 역할을 한다. 인터페이스 package com.java.effective.item38; public interface Operation { double apply(double x, double y); } 열거타입 구현체 packag..

    Read more
  • ordinal 인덱싱의 문제점 배열 또는 리스트에서 원소를 꺼낼때 ordinal 메서드로 인덱스를 얻는 코드가 있다. package com.java.effective.item37; public class Plant { enum LifeCycle { ANNUAL, PERNNIAL, BIENNIAL} final String name; final LifeCycle lifeCycle; public Plant(String name, LifeCycle lifeCycle) { this.name = name; this.lifeCycle = lifeCycle; } @Override public String toString() { return name; } } 이 식물들을 배열 하나로 관리하고, 생애주기(한해살이, 여러해..

    Read more
  • 비트 필드 열거 상수 열거한 값들이 주로 집합으로 사용될 경우 예전에는 각 상수에 서로 다른 2의 거듭제곱 값을 할당한 정수 열거 패턴을 사용해왔다. 오래된 기법 package com.java.effective.item36; public class Text { public static final int STYLE_BOLD = 1

    Read more
  • ordinal 메서드의 문제점 대부분의 열거 타입 상수는 하나의 정숫값에 대응된다. 그리고 모든 열거 타입은 해당 상수가 그 열거 타입에서 몇번째 위치인지를 반환하는 ordinal 메서드를 제공한다. 예제 Ensemble.java package com.java.effective.item35; public enum Ensemble { SOLO, DUET, TRIO, QUARTET; // ordinal() : 선언 순서 대로 정수값 반환 public int numberOfMusicians() { return ordinal() + 1; } } Enum.java 의 ordinal() public final int ordinal() { return ordinal; } 이는 아주 위험한 코드다. 상수 선언 순서를 ..

    Read more
  • 정수 열거 패턴 열거 타입은 일정 개수의 상수 값을 정의한 다음, 그 외의 값은 허용하지 않는 타입이다. 정수 열거 패턴 package com.java.effective.item34; public class Main { public static final int APPLE_FUJI = 0; public static final int APPLE_PIPPIN = 1; public static final int APPLE_GRANNY_SMITH = 2; public static final int ORANGE_NAVEL = 0; public static final int ORANGE_TEMPLE = 1; public static final int ORANGE_BLOOD = 2; } 위 코드는 자바에서 열거타입을..

    Read more
  • 이종 컨테이너 패턴 (type safe heterogeneous container pattern) 제네릭은 Set, Map 등의 컬렉션과 ThreadLocal, AtomicReference 등의 단일원소 컨테이너도 흔히 쓰인다. 이런 모든 쓰임에서 매개변수화되는 대상은 원소가 아닌 컨테이너 자신이다. 따라서 하나의 컨테이너에서 매개변수화할 수 있는 타입의 수가 제한된다. 예를들어, Set에는 원소의 타입을 뜻하는 단 하나의 타입 매개변수만 있으면 되며, Map 에는 key, value의 타입을 뜻하는 2개만 필요한 식이다. 더 유연한 방식이 필요할때가 있다. 데이터베이스희 행(row)은 임의 개수의 열(column)을 가질 수 있는데, 모두 열을 타입 안전하게 이용할 수 있다면 더 편할 것이다. 여기에 ..

    Read more
  • 가변인수 메서드 가변인수(varargs) 메서드와 제네릭은 함께 사용이 어렵다. 가변인수는 메서드에 넘기는 인수의 개수를 클라이언트가 조절할 수 있게 해준다. 가변인수 메서드를 호출하면 가변인수를 담기 위한 배열이 자동으로 하나 만들어진다. 그런데 내부로 감춰야 했을 이 배열을 클라이언트에 노출시키는 문제가 생겼다. 그 결과 varargs 매개변수에 제네릭이나 매개변수화 타입이 포함되면 알기 어려운 컴파일 경고가 발생한다. 실체화 불가 타입은 런타임에는 컴파일 타임보다 타입 관련 정보를 적게 담고 있다. 그리고 거의 모든 제네릭과 매개변수화 타입은 실체화되지 않는다. 메서드를 선언할때 실체화 불가 타입으로 varargs 매개변수를 선언하면 컴파일러가 경고를 보낸다. 가변인수 메서드를 호출할 때도 vara..

    Read more
  • 불공변 타입 매개변수화 타입은 불공변(invariant)이다. 즉, 서로 다른 타입 Type1, Type2 가 있을때 List은 List의 하위 타입도 상위 타입도 아니다. 예를들어, List 은 문자열만 넣을 수 있고, List는 어떤 객체도 넣을 수 있기 때문에 List은 List의 하위타입이 아니다. 이는 List이 List가 하는 일을 제대로 수행하지 못하므로 하위 타입이 될 수 없다는 결론이다. 와일드 카드 타입으로의 변경 Stack 의 public API 추린 코드 public class Stack { public Stack(); public void push (E e); public E pop(); public boolean isEmpty(); } 여기에 일련의 원소를 스택에 넣는 메서드를 ..

    Read more
  • Copyright 2024. GRAVITY all rights reserved