1️⃣ 정적 팩터리 메서드란? 클라이언트가 클래스의 인스턴스를 얻는 수단은 다음의 두가지가 존재한다. > **1) public 생성자 2) 정적 팩터리 메서드(static factory method)** 정적 팩터리 메서드는 🌟클래스의 인스턴스를 단순히 반환하며
🙏선택 매개변수가 많을 경우 활용 가능한 여러 패턴들 중에, 빌더 패턴에 대해 알아본다. 1️⃣ 점층적 생성자 패턴 정적 팩터리와 생성자에는 제약이 하나 존재한다. 바로 필수가 아닌 선택적 매개변수가 많을수록 대응이 힘들다는 점인데, 보통 점층적 생성자 패턴을 즐겨
싱글턴(singleton)이란, 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말한다. 전형적인 예로는, 함수와 같은 무상태 객체나 설계상 유일해야 하는 시스템 컴포넌트를 들 수 있다. 하지만, 클래스를 싱글턴으로 만들면 이를 사용하는 클라이언트를 테스트하기가 어려
단순히 정적 메서드와 정적 필드만을 담은 클래스들은, 객체 지향적이지 않은 것처럼 보이지만 나름의 쓰임새가 존재한다. 다음의 예시들을 봐보자. > 💡 정적 메서드와 정적 필드만을 담은 클래스 예시 1) java.lang.Math, java.util.Arrays 2)
1️⃣ 들어가기 많은 클래스가 하나 이상의 자원에 의존하는 경우가 많다. 이럴때 우리는 주로 정적 유틸리티 클래스(아이템 4) 혹은 싱글턴(아이템 3)으로 구현하고는 한다. 맞춤법 검사기가 사전에 의존하는 예시를 봐보자. ▶️ 정적 유틸리티 잘못 사용한 예 ▶️
1️⃣ 들어가기 > 불필요한 객체 생성을 피하는 방법들에 대해 알아보자. 똑같은 기능의 객체를 매번 생성하기 보다는, 객체 하나를 재사용하는 편이 좋을 때가 많다. 예를 들어, 불변 객체(아이템 17)은 언제든지 재사용 가능하다. 해당 코드는 실행 시 마다 Stri
메모리를 직접 관리해야 하는 C, C++와 달리, 자바는 다 쓴 객체를 알아서 회수해가는 가비지 컬렉터를 가지고 있다. 그렇다고 해서, 메모리 관리에 더 이상 신경 쓰지 않아도 된다는 말은 아니다. 1️⃣ 메모리 누수 주범(1):배열 ▶️ 메모리 누수 예제 겉으로
자바에서 제공하는 두가지 객체 소멸자인 Finalizer, Cleaner을 왜 지양해야 하는지 알아보자. 참고로 Finalizer 는 자바 9 에서는 Deprecated 되었고, Cleaner 가 나왔지만 역시 예측 불가능하고 느리며 불필요하다.
자바 라이브러리에는 close() 메서드를 호출해 직접 닫아줘야 하는 자원이 많다. ex) InputStream, OutputStream, java.sql.Connection이런 자원 중 상당수가 안전망으로 finalizer를 활용하고 있지만, 믿음직스러지 못하다.👉
dd
Object의 기본 toString 메서드는, 우리가 작성한 클래스에 적합한 문자열을 거의 반환해주지 못하고 단지 클래스\_이름@16진수로\_표시한\_해시코드 만을 반환 한다. 예를 들어, PhoneNumber@abbd 를 반환해준다.하지만 이 형태보다는, 전화번호를
compareTo는, 🌟1)단순 동치성 비교에 더해 순서까지 비교할 수 있으며, 2)제네릭(Generic)하다는 두 가지를 제외하면 equals와 동일하다._ (단, Object의 메서드가 아니다)_ Comparable을 구현했다는 것은, 클래스의 인스턴스들에 자연
잘 설계된 컴포넌트는, 🌟모든 내부 구현화 데이터 정보를 외부로부터 완벽히 숨겨, 구현과 API를 깔끔하게 분리🌟한다. 오직 API를 통해서만 다른 컴포넌트와 소통하며 서로의 내부 동작 방식에 개의치 않는 이 개념을, 바로 정보 은닉(캡슐화) 라고 한다. 🔗 정
불변 클래스란, 🌟인스턴스의 내부 값을 수정할 수 없는 클래스이며 불변 인스턴스에 간직된 정보는 고정되어 객체가 파괴되는 순가까지 절대 달라지지 않는다. ex) 자바 플랫폼 라이브러리의 String, BigInteger, BigDeciaml, 기본 타입의 박싱된 클
1️⃣ 상속의 위험성 👉상속(클래스가 다른 클래스를 확장) 은 코드를 재사용하는 강력한 수단이지만, 다른 패키지의 구체 클래스를 상속하는 일은 위험하다. 메서드 호출과 달리 상속은 캡슐화를 깨뜨린다. 즉, 릴리스마다 내부 구현이 달라질 수 있는 상위 클래스로 인해
상속을 고려한 설계와 문서화란 정확히 무엇을 뜻하는지 알아보자. 상속을 위한 좋은 설계란? 1️⃣ 먼저, 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지(자기사용) 문서로 남거야 한다. 즉, 공개된 메서드에서 호출되는 자신의 또 다른 메서드가
🔗 자바는 1)인터페이스와 2)추상 클래스 두가지를 통해 다중 구현 메커니즘 을 제공하고 있다.둘의 가장 큰 차이는 추상 클래스가 정의한 타입을 구현한 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다는 점이다.(단일 상속으로 인해 새로운 타입 정의하는데 제약
1️⃣ 중첩 클래스 중첩 클래스(nested class)란, 다른 클래스 안에 정의되어 자신을 감싼 바깥 클래스에서만 쓰여야 하는 클래스를 의미한다. > 📚* 중첩 클래스 종류* 정적 멤버 클래스, (비정적)멤버 클래스, 익명 클래스, 지역 클래스 👉 이번 아이
소스 파일 하나에 톱 레벨 클래스를 여러개 선언하는 것은, 심각한 위험을 감수해야 하는 행위이다. 한 클래스를 여러 가지로 정의할 수 있으며, 그 중 어느 것을 사용할지는 어느 소스를 먼저 컴파일하느냐에 따라 달라지기 때문이다. 구체적인 예시를 들어보자. ▶️ 두
제네릭 클래스 혹은 인터페이스란, 클래스와 인터페이스 선언에 타입 매개변수가 쓰인 것을 말한다. 각각의 제네릭 타입은 일련의 매개변수화 타입을 정의한다. 📚 제네릭 형식클래스/인터페이스 이름<실제 타입 매개변수>제네릭 타입을 하나 정의하면, 그에 딸린 로 타입(
제네릭을 사용하면서 마주칠 수 있는 컴파일러 경고들은 다음과 같다. 이 중 비검사 경고는 제일 쉽게 제거 가능하기 때문에, 🌟할 수 있는 한 모든 비검사 경고를 제거해야 한다.비검사 경고, 비검사 메서드 호출 경고, 비검사 매개변수화 가변인수 타입 경고, 비검사 변환
📚 공변(covariant)함께 변한다는 것배열은 공변이여서 Sub가 Super의 하위 타입이라면 Sub\[] 또한 Super\[]의 하위 타입이 된다.반면, 제네릭은 불공변(invariant)이기 때문에 서로 다른 타입 Type1과 Type2가 있을 때 List&l
매개변수화 타입은, 서로 다른 타입 Type1과 Type2가 있을 때 List이 List의 하위 타입도 상위 타입도 아닌 "불공변(invariant)" 이다. List은 문자열만, List는 어떤 객체도 넣을 수 있으니 후자가 하는 일을 제대로 수행하지 못해 당연히
열거 타입이란, 일정 개수의 상수 값을 정의한 다음 그 외의 값은 허용하지 않는 타입이다.열거 타입이 생기기 이전에는, 다음 코드처럼 상수를 한 묶음 선언해서 사용하고는 했다.▶️ 정수 열거 패턴1) 타입 안전을 보장할 방법이 없으며 표현력도 좋지 않다.오렌지를 건네야
열거한 값들이 주로 단독이 아닌 집합으로 사용될 경우, EnumSet이 나오기 전에는 각 상수에 서로 다른 2의 거듭제곱 값을 할당한 정수 열거 패턴(아이템 34)를 사용했다. 🔗 비트 필드 열거 상수 ▶️ 비트 필드 열거 상수 비트별 OR를 사용해 여러 상수를
1️⃣ 명명 패턴 전통적으로, 도구나 프레임워크가 특별이 다뤄야 할 프로그램 요소에는 구분되는 명명 패턴을 적용해왔다. 예를 들어, JUnit은 버전 3까지 테스트 메서드 이름을 test로 시작하게끔 하였다. 하지만 이러한 명명 패턴 방식은 여러 단점을 지닌다. 🔗
🔗 함수 객체 생성 수단의 역사 주로 자바에서 함수 타입을 표현할 때, 추상 메서드를 하나만 담은 인터페이스(드물게 추상 클래스)를 사용했다. 이러한 인터페이스의 인스턴스를 함수 객체라고 하며, 특정 함수나 동작을 나타내는데 썼다. 이후 JDK 1.1부터는 함수 객
🔗 메서드 참조 메서드 참조란, 함수 객체를 람다보다 간결하게 만드는 방법이다. ▶️ 람다 map의 merge() 메서드는 키, 값, 함수를 인자로 받으며 주어진 키가 맵 안에 아직 없다면 주어진 {키,값} 쌍을 그대로 저장하는 함수이다. 반대로 키가 이미 있다면
1️⃣ 개요 자바8 부터 람다를 지원하면서, API를 작성하는 모범 사례들도 크게 바뀌었다. 예를 들어, 상위 클래스의 기본 메서드를 재정의해 원하는 동작을 구현하는 템플릿 메서드 패턴 대신 함수 객체를 매개변수로 받는 정적 팩터리나 생성자를 제공하고는 한다. 많이
스트림이란 자바 8부터 다량의 데이터 처리 작업(순차/병렬)을 돕고자 나온 API이며, 두 가지 핵심적인 추상 개념을 제공한다. 스트림 API는 메서드 연쇄를 지원하는 프루언트 API(fluent API)이다. > 🔖 스트림의 추상 개념 1) 스트림(stream)
스트림은 단순한 또 하나의 API가 아닌, 함수형 프로그램에 기초하고 있다. 1️⃣ 스트림 패러다임 스트림 패러다임의 핵심은 계산을 일련의 변환으로 재구성하는 부분이다. 이때 각 변환 단계는 가능한 한 이전 단계의 결과를 받아 처리하는 순수 함수여야 한다. > 🔖
1️⃣ 방어적 복사(Defensive Copy) 자바는 C/C++와 같이 안전하지 않은 언어에서 자주 보는 버퍼 오버런, 배열 오버런, 와일드 포인터 같은 메모리 충돌 오류가 일어나지 않는다는 점에서 안전한 언어이다. 즉 자바로 작성한 클래스는, 무조건 그 불변식이
컬렉션이나 배열같은 컨테이너(Container)가 비었으면 null 을 반환하는 메서드는, 항상 방어 코드를 넣어줘야 한다.즉, 다음과 같이 클라이언트가 null 상황을 처리하는 코드를 추가적으로 작성해야 하는 것이다.null 대신 빈 컨테이너를 할당한다면, 방어 코드
메서드가 "특정 조건에서 값을 반환할 수 없을 때" 취할 수 있는 선택지는 다음과 같이 존재한다.예외를 던진다.반환 타입이 객체 참조라면, Null을 반환한다. 하지만 예외는 정말 예외인 상황에서만 사용해야 하며(아이템 69) 생성 시 스택 추적 전체를 갭처하므로 비용
쓸모 있는 API에는 잘 작성된 문서도 필요하다. 자바에서는 자바독(Javadoc)이라는 유틸리티를 지원하고 있는데, 소스코드 파일에서 문서화 주석이라는 특수한 형태로 기술된 설명을 추려 API 문서로 변환해준다. 🔗 문서화 주석을 다는 방법 1) 공개된 모든 클래
지역변수의 유효 범위를 최소로 줄이면, 코드 가독성과 유지보수성이 높아지고 오류 가능성은 낮아진다. C 언어 지역변수를 코드 블럭의 첫 머리에 선언해야 한다. JAVA 문장을 선언할 수 있는 곳이면 어디서든 변수를 선언 가능하다. 🔗 지역변수의 범위를 줄이는
🔗 For-Each문을 사용하기 이전 전통적 for문을 사용해서 반복하기 ▶️ 컬렉션 순회 ▶️ 배열 순회 while문 보다는 낫지만, 가장 좋은 방법은 아니다. (아이템 57) 다음의 이유를 보자. 반복자와 인덱스 변수는 코드만 지저분하게 할 뿐 꼭 필요한 것
float 과 double 타입은, 이진 부동소수점 연산에 쓰이며 넓은 범위의 수를 빠르게 정밀한 근사치로 계산하도록 설계되었다.따라서, 정확한 결과가 필요할때는 부적합하다. 특히나, 금융 관련 계산에는 사용하면 안된다. 0.1 혹은 10의 음의 거듭제곱 수를 표현할
객체의 실제 클래스를 사용할 상황은, 오직 생성자로 생성할 때 뿐이다.따라서 적합한 인터페이스만 있다면 매개변수 뿐 아니라 반환값, 변수, 필드 전부 인터페이스 타입으로 선언해야 한다. 인터페이스를 타입으로 사용하는 프로그램은 훨씬 유연해지기 때문이다.만약 나중에 구현
자바는 문제 상황을 알리는 타입(throwable)으로 다음의 세가지를 제공한다.검사 예외 : Exception 하위 클래스들런타임 예외 : RuntimeException 하위 클래스들에러 : Error 하위 클래스들해당 세가지 중에 언제 어떠한 타입을 사용하면 좋을지
메서드가 저수준 예외를 처리하지 않고 바깥으로 전파( throws )해버릴 때, 수행하려는 일과 관련 없어 보이는 예외가 튀어나오게 된다. 이는 내부 구현 방식을 드러내어 윗 레벨의 API를 오염시킬 수 있다는 단점이 있다.이 문제를 피하려면, 상위 계층에서는 저수준
Q. 동기화란 무엇일까?다른 스레드가 변경중이여서 일관되지 않은 상태를, 락을 검으로써 다른 스레드가 보지 못하게 막는다. 즉 일관성이 깨진 상태를 볼 수 없게 한다. 락의 보호하에 수행된 모든 이전 수정의 최종 결과를 볼 수 있게 해준다.우리는 자바의 synchron
스케줄링 정책은 운영체제마다 다를 수 있으므로, 프로그램의 성능이 스케줄러에 따라 달라지지 않도록 해야 한다. 아래 세 가지 방안을 지킨다면, 스케줄러에 독립적인 이식성이 높은 프로그램을 만들 수 있다. ☁️ 실행 가능한 스레드 작게 유지하기 실행 가능한 스레드