디폴트 메서드 전통적인 자바 인터페이스를 구현하는 클래스는 인터페이스의 모든 메서드 구현을 제공하거나 슈퍼 클래스의 구현을 상속받아야 한다. 인터페이스를 바꾸고 싶을 때 문제 발생 -> 모든 구현체를 다 고쳐야 함 자바 8 인터페이스의 변화 인터페이스 내부에 정적 메서드 사용 디폴트 메서드 기능 사용 즉 메서드 구현을 포함한 인터페이스를 정의할 수 있다. 기존 코드 구현을 바꾸지 않도록 하면서 인터페이스를 바꿀 수 있다. 결국 추상 클래스? 디폴트 메서드는 주로 라이브러리 설계자들이 사용한다. 정적 메서드와 인터페이스 보통 자바에서는 인터페이스와 인터페이스를 활용할 수 있는 정적 메서드를 정의하는 유틸리티 클래스를 활용한다. (Collection 인터페이스를 활용하는 Collections) 자바 8 이후..
개발 서적
열거 타입의 확장은 불가능? 열거 타입은 활용하기 좋지만 확장할 수 없다는 단점이 있다. 쉽게 말해서 Enum 타입은 상속이 불가능하다. 사실 대부분의 상황에서 열거 타입을 확장하는 것은 좋지 않은 생각이다. 열거 타입은 원소들을 순회할 수 있는데 기반 타입과 확장 타입을 모두 순회하는 방법도 마땅치 않다. 열거 타입은 인터페이스를 구현할 수 있다. 열거 타입을 상속받는 것은 불가능하다. 하지만 열거 타입이 인터페이스를 구현하는 것은 가능하다. 상위 인터페이스를 정의하고 이를 확장한 여러 열거 타입으로 유연하게 여러 열거 타입 구현체를 사용할 수 있다. 아래는 체스 미션에서 사용한 인터페이스와 열거 타입을 사용한 예시이다. 체스 미션에서 활용한 방향 열거 타입 체스 기물인 킹, 퀸, 폰, 룩, 비숍, 나..
11.1 값이 없는 상황을 어떻게 처리할까 클래스 내부에 필드로 객체를 가지는 상황에서 객체가 비어 있고, 해당 필드에 접근하려 하면 NullPointerException이 발생한다. 보수적인 자세로 if (객체 == null)을 많이 사용하여 null을 피해 갈 수도 있을 것이다. 변수를 접근할 때마다 if가 늘어나고 코드 들여 쓰기가 늘어난다. 이와 같은 반복 패턴 코드를 ‘깊은 의심’이라고 한다. null 때문에 발생하는 문제 에러의 근원이다: NullPointerException은 가장 흔한 에러 코드를 어지럽힌다: null 확인 코드를 추가해야 하므로 아무 의미가 없다: null은 아무 의미도 표현하지 않는다. 자바 철학에 위배된다: 자바는 개발자로부터 모든 포인터를 숨겼지만 null은 예외 형..
자바가 람다를 지원하면서 API를 작성하는 방법이 크게 바뀌었다. 특히 함수형 인터페이스를 사용해 메서드마다 다른 동작을 메서드를 사용하는 클라이언트에서 지정해줄 수 있다. 이런 방식을 동작 파라미터화라고 한다. 이를 이용하면 변화하는 요구사항에 효과적으로 대응할 수도 있고 클래스와 클래스 간의 의존을 맺을 때 의존을 끊어줄 수도 있다. 변하는 요구사항에 대응하기 회원들의 리스트에서 어떤 조건에 따라 필터링을 해야 한다고 가정하자. public class Member { private final String name; private final int age; public Member(String name, int age) { this.name = name; this.age = age; } } 회원은 이름..
상속은 코드 중복을 제거하는 강력한 수단이지만 잘못 사용하면 오류를 내기 쉬운 소프트웨어를 만들게 된다. 상속의 문제점 상속은 캡슐화를 깨뜨린다. 하위 클래스가 가지는 상위 클래스에 대한 강한 의존성 때문에 상위 클래스의 구현에 따라 하위 클래스 동작이 의도와는 다르게 동작할 수도 있다. 게다가 상위 클래스의 변화가 하위 클래스까지 전파되어 변화에 맞춰 수정도 계속해주어야 한다. 예를 들어 HashSet을 상속 받는다고 가정하자. 상속받은 하위 클래스는 처음 생성된 이후 몇 개의 원소가 더해졌는지 횟수를 알고 싶어서 횟수를 알 수 있는 기능을 추가했다. public class InstrumentedHashSet extends HashSet { private int addCount = 0; @Overrid..
용어 정리 클래스와 인터페이스 선언에 타입 매개변수가 쓰이면, 이를 제네릭 클래스 혹은 제네릭 인터페이스라 한다. public interface List extends Collection { List 인터페이스는 E라는 원소 타입 매개변수를 받고 이러한 제네릭 클래스와 인터페이스를 통틀어 제네릭 타입이라 한다. 제네릭 타입은 매개변수화 타입을 정의한다. 예를 들어 List라고 했을 때 Integer가 리스트가 받을 수 있는 타입을 정의한 매개변수화 타입이다. 제네릭 타입에는 로 타입이라는 것도 있다. 로 타입이란 타입 매개변수를 사용하지 않은 제네릭 타입을 의미한다. List list; 그렇다면 이 로 타입을 사용하지 말아야 하는 이유는 무엇일까? 로 타입은 타입 안정하지 않다. List rawList ..
자바가 열거 타입을 지원하기 전 로또의 등수를 표현한다고 가정해보자. 열거 타입을 쓸 수 없다면 다음과 같이 표현할 수 있을 것이다. public static final int LOTTO_RANK_FIRST = 1; public static final int LOTTO_RANK_SECOND = 2; public static final int LOTTO_RANK_THRID = 3; public static final int LOTTO_RANK_FOURTH = 4; public static final int LOTTO_RANK_FIFTH = 5; public static final int LOTTO_RANK_NOTHING = 0; 1등은 정수 1로, 5등은 5로, 꽝은 0으로 정수를 열거하여 작성했다. 이렇..
스트림을 사용하면 내부 반복으로 네이티브 자바 라이브러리가 스트림 요소의 처리를 제어할 수 있다. 따라서 개발자는 컬렉션 데이터 처리 속도를 높이려고 따로 고민할 필요가 없다. 컴퓨터의 멀티코어를 활용해서 파이프라인 연산을 실행할 수 있다는 점이 중요한 특징이다. 7.1 병렬 스트림 컬렉션에 parallelStream을 호출하면 병렬 스트림이 생성된다. 병렬 스트림이란 각각의 스레드에서 처리할 수 있도록 스트림 요소를 여러 청크로 분할한 스트림이다. 따라서 모든 멀티코어 프로세서가 각각의 청크 처리를 할당할 수 있다. 병렬 실행이 무조건 빠른 것은 아니다. static long sum(int n) { long sum = 0; for (int i = 0; i < n; i++) { sum += 1; } re..