코드를 보면 of, from 등 static 메서드를 많이 본 적이 있다. 정적 팩토리 메서드를 사용하면서 장점과 유의할 점에 대해서 알아보자new Store(a, b, c) < - > Store.newInstance(a, b, c)생성자와는 다르게 네이밍을 지어
생성자가 3개까지는 점층적 생성자 패턴을 사용해도 크게 문제가 없다. 점층적 생성자 패턴이란, 평소 생성자를 생성하는 방식으로 생성자를 정의하는 패턴이다.이렇게 생성자가 3개 이상에 점층적 생성자 패턴을 적용해보았다. 특히 필수 생성자가 3개를 초과하면 굉장히 복잡해진
싱글턴이란 오직 하나의 인스턴스를 보장하는 방식을 이야기한다. 싱글턴 클래스의 예이다.위 코드는 Elvis INSTANCE를 초기화할때 한번만 인스턴스를 초기화한다.다만 private 생성자를 reflection을 활용해 호출할 수 있기는 하다.정적 팩토리 메서드를 활
이전에 builder 패턴을 사용할 때 인스턴스를 생성하는 생성자를 private 또는 protected를 사용했다. 그 이유는 외부에서 직접 생성자를 호출하는 것이 아닌 오직 nested class의 builder 만이 생성자를 호출하기 위함이였다. 즉 어떤 클래스
특정 자원을 사용하는 경우 private static final을 이용해 인스턴스를 생성해서 활용하거나 싱글턴을 사용하는 경우가 있다. 이 경우 테스트가 쉽지 않다. 왜냐하면 private으로 내부적으로 이미 생성해두는데 테스트에서 이를 접근할 권한이 없기 때문이다.
Java의 String은 String Constant Pool 영역에 저장된다. 그래서 동일한 String을 호출하는 경우 매번 인스턴스를 생성하는 것이 아니라 pool에 저장된 문자열을 가져온다. Integer나 Long의 경우에도 constant pool에 저장한다
자바의 경우 메모리를 자동으로 가비지 컬렉터가 관리해주기 떄문에 C, C++ 보다 메모리 관리하기가 편하다. 그러나 자칫 메모리를 관리할 필요 없다고 생각할 수도 있는데, 그것은 사실이 아니다. 메모리 누수 Case
c++에서는 객체 소멸자가 기본으로 제공되지만. 자바의 경우 finalizer와 cleaner를 활용해 구현해야한다. finalizer의 경우 java 9 이후로 deprecate 되었고, 그 이후 대안으로 cleaner를 사용한다.메모리와 외부 시스템 연결과 같은 작
일반 객체를 소멸하는데는 GC만으로 충분하다. 그러나 외부 시스템 자원과 연동을 위해 InputStream, OuputStream, sql.Connection 등을 활용한다면 사용후 자원을 닫아주는 것이 필요하다. 이럴 때 try-with-resource를 활용할 수
값은 표현하는 것이 아닌 동작을 표현하는 개체는 equals를 재정의할 이유가 없다. 그 중 하나의 예는 Thread이다.프로그래밍의 기본 원칙중 하나로 굳이 사용하지 않을 메서드는 구현하지 않는 것이다. equals를 비교할 일이 없는데 구현하는 것은 오버 프로그래밍
Equals를 구현했다면 HashCode 또한 반드시 구현해야 한다. 그 이유는 HashMap이나 HashSet과 같은 컬렌션의 원소로 사용하는 경우 Equals와 HashCode를 사용하는데 문제를 일으킬 수 있다.HashMap의 getNode 메서드로 실제 key를
toString을 재정의하지 않으면 16진수의 hashCode를 반환하고 디버깅시 이해하기 힘들다. toString으로 용도에 맞게 재정의 하면 디버깅시 객체 상태 파악에 용이하고 println, printf 나 assert구문에서도 훨씬 보기 좋게 쓰일 수 있다.to
Cloneable은 복제해도 되는 클래스임을 명시하는 용도의 믹스인 인터페이스이다.Cloneable은 조금 희한하게 설계가 되었는데 그 이유는 interface 메서드에 clone이 없다는 점이다. 이것은 자바를 만들 때 의도한 목적으로 만들지 못한 잘못된 예라고 책에
정렬 또는 자동 정렬되는 컬렉션에서 굉장히 유용하게 사용할 수 있다. 즉 클래스에 Comparable을 구현한다는 것은 클래스에게 natural order (기본 대소 비교 기능)을 제공해주는 것이라 할 수 있다. 적은 노력으로 굉장히 큰 이득을 얻을 수 있기 때문에
객체 지향하면 떠오르는 3가지가 있다. 바로 다형성, 캡슐화, 상속 이다. 이 중 캡슐화는 잘 설계된 컴포넌트 설계에 필수적인 요소이다. 캡슐화란 정보은닉이라고도 하며 클래스의 내부 구현을 숨겨 구현과 API를 깔끔하게 분리하는 과정이다.오직 API를 통해서만 서로 다
위의 코드는 내부 구현을 외부 API로 그대로 사용하고 있다. 이것의 문제점은 내부 구현과 외부 API가 합쳐져 있기 때문에 나중에 코드 수정이 쉽지 않다는 점이다. 내부 구현은 언제든 수정 가능하고 외부로 노출되는 API는 좋은 방법이 아니다. 외부 API가 수정되면
ㅗㅗ
상속은 객체지향에서 강력한 도구 중 하나이다. 상속을 통해 코드를 재사용하고, 템플릿 패턴으로 활용할 수 있다. 물론 문서화가 잘 되어 있고, 명확하게 확장할 목적으로 사용하면 굉장히 좋지만 일반적으로 상속은 캡슐화를 깨뜨릴 위험이 있다.상속은 java에서 protec
상속은 잘못될 위험성이 있다. 상속은 하위클래스가 상위 클래스를 재사용함과 동시에 추가 또는 새로운 api가 추가될 수 있는 데 이 때 sub 클래스는 super 클래스를 의존하게 된다. 이런 의존이 뜻하지 않은 결과를 만들어 낼 수 있기 때문에 상속의 경우 미리 이를
자바에서는 다중 구현 메커니즘은 인터페이스와 추상 클래스, 이렇게 2가지이다. 이 둘의 가장 큰 차이는 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다는 점이다. 자바의 경우 단일 상속만 지원하니, 추상 클래스 방식은 새로
자바 8 이전의 인터페이스는 모든 클래스가 현재의 인터페이스에 새로운 메서드가 추가될 일은 없다는 생각으로 가정하고 작성했다. 그렇기에 메서드를 인터페이스에 추가하면 컴파일 에러가 발생하고 해당 인터페이스를 타입으로 삼는 모든 구현 클래스에 추가된 메서드를 모두 구현해
객체지향의 사실과 오해 라는 책에서 의미를 빌리면 타입은 개념이다. 개념이란 우리가 표현하고자 하는 물체의 본질이라 할 수 있다. 예를 들면 이상한 나라의 엘리스에서 정원사, 병정, 하트퀸, 하트 킹 등은 트럼프 인간으로 볼 수 있고 트럼프 인간은 납작한 트럼프 카드
enum 을 이용해 클래스의 Shape을 표현하고 Shape에 따라 area의 분기문이 생긴다. 이 코드의 문제점은 너무 장황하고 메모리가 낭비된다. 타입에 따라 전혀 사용하지 않는 변수가 생기고 area의 코드는 shape 분기마다 계산이 달라지므로 코드가 길어졌다.
중첩 클래스란 nested class로 불리고 클래스 내부에 선언한 클래스이다. 해당 클래스는 바깥 클래스가 활용하며, 그 외에 활용도가 있다면 다른 톱 클래스로 만들어야 한다.클래스의 종류는 멤버 클래스, 지역 클래스, 정적 멤버 클래스, 익명 클래스 이렇게 4가지이
보통 클래스는 하나의 책임을 가지고 정의한다. 한 파일에 하나의 클래스가 있다면 클래스를 파악하기 쉽고 이해하기 쉽다.실수로 클래스를 중복 정의하게 되면, 컴파일 순서에 따라 에러가 발생하거나 다른 동작을 수행하게 된다.예를 들어보자만약 javac Main.java D
우리가 제네릭 타입을 정의할 때와 같이 List<E>로 정의한다. 읽을 때는 List of E 로 읽는다. 그러나 꺽쇠 없이, 매개변수 타입을 정하지 않고 List 타입만을 사용하면 이를 로 타입이라 한다.로 타입을 사용하면 제네릭을 사용한다고 할 수 없다. 그리
제네릭을 사용하면 비검사 형변환 경고비검사 메서드 호출 경고비검사 매개변수화 가변인수 타입 경고비검사 변환 경고과 같은 경고를 마주칠 수 있다. 대부분은 컴파일러가 알려준대로 처리하면 더 이상 해당 경고는 나타나지 않는다. 즉, 런타임에 ClassCastExceptio
배열은 공변, 제네릭은 불공변이라 한다. 공변이란 무엇인가?공변은 Sub가 Super의 하위 타입이라면 해당 타입 즉 배열에서도 Sub\[]가 Super\[]의 하위 타입이 된다. 즉, 이전 특성이 타입이 변해도 공변이라면 동일하게 특징을 가져온다는 특성이 있다.제네릭
형변환은 잠재적으로 런타임 예외를 일으킬 가능성이 있다. item28에서 공변인 배열보다 리스트를 활용하라고 하는데 그런 예가 적절한 예라고 할 수 있다. 제네릭을 활용하면 타입에 대한 안정성을 높이고 컴파일 단계에서 걸러낼 수 있기 때문에 훨씬 안정적인 코드라 할 수
Collections에서 제공하는 정적 메서드는 대부분 제네릭 메서드이다. 제네릭 메서드에 장점은 타입에 유연하다는 점이다. 물론 제네릭을 사용한다면 유의해야 할 점이 있다.이전에도 나온 내용이지만 로 타입을 사용하지 말것, 타입 경고를 반드시 해결해야 한다.아주 간단
item 30 에서 잠깐 한정적 와일드 카드를 쓴 경우가 있다. 바로 상속을 고려해서 제네릭을 짜야 할 때이다. 제네릭은 기본적을 불공변이다. List<Object>와 List<String>은 서로 아무런 관계가 없는 타입이라는 뜻이다. 그러나 경우에 불공변
배열로 선언하든 제네릭으로 선언하든 가변인수로 선언하면 내부적으로 배열이 만들어진다. 문제는 배열은 공변이고 제네릭은 불공변이다. 제네릭은 컴파일시에 타입을 체크하지만 배열은 런타임에 타입을 체크한다. 이러한 불일치성과 제네릭으로 선언해도 내부적으로 배열로 생성되기 때
Map 또는 Set에 사용하는 타입보다 훨씬 유연하고 확장 가능한 타입을 제공하고 싶을 때가 있다. 예를 들면 임의의 데이터 베이스를 생각해보자 각 레코드별로 임의의 컬럼을 가질 수 있다. 이 때 임의의 컬럼들을 제네릭을 활용해 type-safe하게 가져오고 저장할
상수를 이용해서 열거 패턴을 사용하면 구현은 쉽지만 문제점이 있다. 바로 실수할 가능성이 높아지고, 컴파일러를 통해서 어떤 오류나 경고도 볼 수 없다. 코드를 살펴 보자일부로 실수를 유도하도록 코드를 짯는데 만약에 APPLE_JUICE == ORANGE_JUICE 를
enum을 사용하다 보면 Ordinal() 함수를 볼 수 있다. Ordinal에 대해서 살펴보면 다음과 같다.enumeration의 ordinal(어떤 순서를 나타내는것, enum 정의의 각 포지션)를 리턴한다. 일종의 선언한 열거형 상수 인스턴스들의 인덱스 정도로 이
자바에서 Reflection에 활용되는 Modifier의 클래스를 보면 Modifier는 비트를 활용해서 해당 객체가 가지고 있는 여러 특성을 잘 표현한다.Modifier는 비트 포지션을 활용하여 실제로 객체가 가진 여러 특성을 표현한다.그러나 이런 방법은 현대적인 방
index로 접근하는 것은 항상 ArrayIndexOutOfBoundsException에 노출된다. 이렇게 검출되는 것도 운이 좋은 케이스이고, 그렇지 않은 경우는 런타임 상에서 로직을 실수하기 쉽다.예제를 통해 알아보자식물은 생애 주기 타입을 가지고 있고 이를 상태로
기본적으로 enum은 자바에서 제공하는 완벽한 싱글턴 형태이다. 컴파일 시점에 이미 인스턴스를 생성하고 이를 접근하는 식으로 사용한다. 그러나 이것에 상속과 같은 기능으로 확장한다면 가능은 하겠지만, 싱글턴 취지에 맞지 않다.예를 들어 보자. 만약 상속을 허용하는 경우
junit을 이용해 테스트 코드를 작성할 때 @Test 어노테이션이 익숙하다. 하지만 junit 3 이하 버전에서는 명명 패턴을 활용해 테스트 코드를 인식했다. test라는 글자가 메서드에 붙어야 하는데 잘못된 형식으로 작성하거나 tset과 같이 오타의 경우 테스트 코
@Override 어노테이션은 상속시에 subtype이 부모 type이 메서드를 덮어씌워서 사용할 때 사용하는 마커 어노테이션이다. 이를 통해 해당 메서드가 override 되었음을 명확히 알 수 있고 실수를 줄일 수 있다. 만약 @Override가 없다면 어떻게 될까
마커 인터페이스는 아무 메서드도 정의하지 않고 단순히 타입을 정의하기 위해 사용하는 인터페이스이다. 예를 들면 Cloneable과 Serializable 등을 들 수 있다. 이들은 특정 메서드를 정의하지 않았지만 이를 구현한 클래스는 해당 타입의 하위 타입임을 명시해
과거에는 특정한 임의의 클래스를 설계해서 주입해야 하는 경우 익명 클래스를 사용할 수 밖에 없었다.sort는 Comparator 타입을 입력받고 직접 비교 로직을 구현함으로써 컬렉션을 커스텀 sort 가능해진다. 그러나 java 8 이후 lambda 를 지원하면서 함수
간단한 식과 단일 메서드를 익명클래스로 구현해야하는 경우 item 42에서 이미 람다가 효율적임을 알게 되었다. 그러나 람다함수보다 조금 더 가독성을 높일 수 있는 경우는 메서드 참조이다.위의 예제는 Map 타입에서 merge 메서드를 실행한 경우다. 만약 intell
책에서는 템플릿 패턴보다는 어떤 효과가 있는 함수 객체를 받는 정적 팩토리나 생성자를 제공하는 것이다. 말이 어려운데 조금 더 간단히 이야기하면 상속 패턴을 활용해서 구체적인 로직을 구현하는 것보다 로직을 구현한 함수형 객체를 주입하는 것이 조금 더 유연하고 확장성 좋
스트림 파이프라인은 다량의 데이터 처리 작업(순차 또는 병렬)을 처리하기 위해 java 8에 추가된 API이다.기본 타입 지원은 int, long, double을 지원한다스트림 파이프라인은 소스 스트림에서 시작해 중간 연산 과정을 거쳐 종단 연산으로 끝난다. 이 떄 중
stream pipe line은 함수형 프로그래밍 패러다임에 기초한다. 함수형 프로그래밍이란 상태가 아닌 인자에만 영향을 받아 변화하는 함수를 조합해서 프로그래밍하는 패러다임이다. 자세한건 해당 범위를 넘어가므로 생략한다.stream의 패러다임은 계산을 일련의 변환으로
ㅁ