불필요한 객체 생성을 피하라 String name = new String("sasca37"); // 매번 인스턴스 생성 String name2 = "sasca37"; // 상수풀 사용 똑같은 기능의 객체를 매번 생성하기보다 객체 하나를 재사용하는 편이 나을 때가 많다. 불변 클래스라면 (가변 클래스여도 변경의 여지가 없다면) 생성자보다 정적 팩터리 메서드를 사용하여 객체를 재사용하는 것이 효율적이다. static boolean isRomanNumeral(String s) { return s.matches("^(?=.)M*(C[MD]|D?C{0,3})" + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$"); } 해당 방식의 문제는 String.matches 메서드를 사용한다는 데 있다. 이..
자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 많은 클래스가 하나 이상의 자원에 의존한다. 예를 들어 맞춤법 검사기는 사전(dictionary)이 없으면 검사를 할 수 없다. 이러한 맞춤법 검사기와 사전과의 관계를 의존 관계라고 하며, 이런 클래스를 정적 유틸 클래스로 구현한 모습을 자주 볼 수 있다. 정적 유틸 클래스를 잘못 사용한 예 import java.util.List; public class SpellChecker { private static final KoreaDictionary dictionary = ...; private SpellChecker() {}; public static boolean isValid(String word) {...}; public static List su..
인스턴스화를 막으려거든 private 생성자를 사용하라 java.lang.Math 나 java.util.Collections 처럼 단순히 정적 메서드와 정적 필드만을 담은 클래스를 만들고 싶은 경우가 있을 것이다. 해당 유틸리티 클래스들은 인스턴스로 만들어 쓰려고 설계한게 아니지만, 생성자를 명시하지 않아도 컴파일러가 자동으로 빈 생성자를 만들어준다. 추상클래스는 abstract 명시로 인스턴스화 할 수 없기 때문에 추상클래스로 해결할 수 있지만, 추상클래스를 상속하여 하위 클래스에서 인스턴스화를 한다면 해결되지 않는다. public abstract class UtilityClass { public abstract void print(); } class Child extends UtilityClass {..
private 생성자나 열거 타입으로 싱글톤임을 보장하라 싱글톤은 인스턴스를 오직 하나만 생성할 수 있도록 보장해주는 디자인 패턴을 의미한다. 대표적인 예로는 stateless한 객체나 함수 상에 유일하게 설계하는 경우이다. 즉, 반대로 싱글톤 객체는 stateful하게 설계하면 안된다. 싱글톤 관련 포스팅 : https://sasca37.tistory.com/20 클래스를 싱글톤으로 설계하면 이를 사용하는 클라이언트를 테스트하기가 어려워 질 수 있다. 타입을 인터페이스로 정의한 다음 그 인터페이스를 구현해서 만든 싱글톤이 아니라면, 싱글톤 인스턴스를 mock 객체로 대체할 수 없기 때문이다. 싱글톤 방식은 public static final 방식과 정적 팩터리 방식, Enum 방식이 존재한다. 앞의 두..
생성자에 매개변수가 많다면 빌더를 고려하라. 정적 팩터리 메서드와 생성자에는 매개변수가 많을수록 대응이 어렵다는 공통점이 있다. 예를 들어, 개발자가 실수로 매개변수의 값의 순서를 다르게 대입했으나, 하필 타입이 같으면 컴파일 오류가 발생하지 않는 경우가 있다. 이 문제를 해결하기 위한 대안으로는 자바 빈즈 패턴과 빌더 패턴이 존재한다. 생성자나 정적 팩터리가 처리해야 할 매개변수가 많다면 빌더 패턴을 선택하는 것이 바람직하다. 점층적 생성자 패턴 점층적 생성자 패턴은 필수 매개변수만 받는 생성자를 시작으로 선택 매개변수를 늘려가는 방식으로 매개변수가 많아질수록 클라이언트 코드를 작성하기 어렵다. public class Book { private final String title; private int ..
생성자 대신 정적 팩터리 메서드를 고려하라 정적 팩토리 메서드(Static Factory Method)란 객체 생성의 역할을 하는 클래스 메서드라는 의미를 갖고 있다. 즉, 생성자를 통해 객체를 생성하는 것이 아닌 메서드를 통해 객체를 생성하는 것을 의미한다. class Book { private String title; private long isbn; public static Book createByIsbn(long isbn) {...}; public static Book createByTitle(String title){...}; } 클래스는 생성자와 별도로 정적 팩터리 메서드를 제공할 수 있다. 장점 이름을 가질 수 있다. BigInter(int, int, Random) 보다 BigInteger...
부하 테스트 서비스 운영에는 현재 시스템이 어느 정도의 부하를 견딜 수 있는지 확인하고, 한계치에서 병목이 생기는 지점을 파악하고 장애 조치와 복구를 사전에 계획해두는 것이 중요하다. 각 시스템의 응답 성능 및 한계치를 알아보는 것을 부하 테스트라고 한다. 가용성 가용성이란 시스템이 서비스를 정상적으로 제공할 수 있는 상태를 의미한다. 가령, 한 대의 서버에 문제가 생겨도 사용자는 인지할 수 없도록 하는 것이 가용성을 높이는 것이고, 단일 장애점(SPOF)를 없애고 확장성있는 서비스를 만들어야 한다. 가용성은 uptime 등의 지표로 측정되기도 하며, IDC, 네트워크, 하드웨어, 소프트웨어 등의 장애 혹은 점검기간, 그리고 높은 부하에 따른 타임아웃 등으로 서비스를 이용할 수 없는 경우 가용성이 낮아진..
Hash Table Hash Table은 key와 value의 구조를 자료구조다. Hash Function을 통해 Hash 값을 구해서 인덱스로 사용하고, 이 인덱스가 key가 되며, key를 통해 value를 얻을 수 있다. 버킷에 있는 해시값을 인덱스로 접근하기 때문에 탐색 시간 복잡도는 O(1)이므로 탐색 시에 효율적인 알고리즘이다. 다만 해시 테이블은 해시 함수를 구하는 과정에서 중복이 발생할 수 있으며, 이를 해시 충돌(Hash Collision)이라 한다. 해시 테이블은 다음과 같이 해시 함수, 버킷, 엔트리를 통해서 값을 보관한다. 충돌 해결 방법 해시 충돌 해결 방법으로는 개방 주소법(open-addressing)과 체이닝(chaining) 기법이 있다. 개방 주소법(open-address..