분류 전체보기

    클린 코드(Clean Code) - 1장, 2장, 3장

    신은 세세함에 깃들어 있다. 책은 각각의 큰 주제에 대해서 17개의 장으로 구성되어 있다. 해당 글에서는 책의 모든 내용을 다루지는 않는다. 현재 나에게 필요한 내용이거나 다시 한번 상기해야 하는 점들만 다룰 것이므로 이 점에 대해서는 양해를 구한다. 1장. 깨끗한 코드 🌊 워드 커닝햄(Ward Cunningham)은 '깨끗한 코드는 읽으면서 놀랄 일이 없어야 한다'라고 말한다. 읽으면서 짐작한 대로 돌아가는 코드가 깨끗한 코드다. 각 모듈은 다음 무대를 준비하고, 모듈을 읽으면서 다음에 벌어질 상황이 보여야 한다. 2장. 의미 있는 이름 🌼 좋은 이름을 지으려면 많은 시간이 걸리지만 좋은 이름으로 절약하는 시간이 훨씬 더 많다. 생성자를 중복정의할 때는 정적 팩토리 메서드를 사용한다. 추상적인 개념 하..

    equals를 재정의하려거든 hashCode도 재정의하라(1) - [3장. 모든 객체의 공통 메서드(아이템11)]

    equals를 재정의한 클래스 모두에서 hashCode도 재정의해야 한다. 그렇지 않으면 hashCode 일반 규약을 어기게 되어 해당 클래스의 인스턴스를 HashMap이나 HashSet 같은 컬렉션의 원소로 사용할 때 문제를 일으킬 것이다. 다음은 Object 명세에서 발췌한 hashCode에 대한 규약이다. equals 비교에 사용되는 정보가 변경되지 않았다면 hashCode는 매번 같은 값을 리턴해야 한다. 정보가 변경되거나, 애플리케이션을 다시 실행했다면 값이 달라질 수 있다. 두 객체에 대한 equals가 같다면, hashCode의 값도 같아야 한다. 두 객체에 대한 equals가 다르더라도, hashCode의 값은 같을 수 있다. 하지만, 해시 테이블 성능을 고려해 다른 값을 리턴하는 것이 좋..

    equals는 일반 규약을 지켜 재정의하라(3) - [3장. 모든 객체의 공통 메서드(아이템10)]

    이번 글에서는 지금까지의 내용을 종합해서 양질의 equals 메서드 구현 방법과 주의 사항에 대해서 알아보고자 한다. 1. equals 구현 방법 == 연산자를 사용해 입력이 자기 자신의 참조인지 확인한다. instanceof 연산자로 입력이 올바른 타입인지 확인한다. 입력을 올바른 타입으로 형변환한다. 입력 객체와 자기 자신의 대응되는 '핵심' 필드들이 모두 일치하는지 하나씩 검사한다. float와 double을 제외한 기본 타입 필드는 == 연산자로 비교하고, 참조 타입 필드는 각각의 equals 메서드로, float과 double 필드는 각각 정적 메서드인 Float.compare(float, float)와 Double.compare(double, double)로 비교한다. (float와 doubl..

    equals는 일반 규약을 지켜 재정의하라(2) - [3장. 모든 객체의 공통 메서드(아이템10)]

    이번 글에서는 equals 메서드를 재정의할 때 반드시 지켜야 하는 일반 규약 5가지를 조금 더 자세히 알아보고자 한다. 1. 반사성(reflexivity) A.equals(A) == true 반사성은 단순히 말하면 객체는 자기 자신과 같아야 한다는 뜻이다. 이 요건은 일부러 어기는 경우가 아니라면 만족시키지 못하기가 더 어려워 보인다. 2. 대칭성(symmetry) A.equals(B) = B.equals(A) 대칭성은 두 객체는 서로에 대한 동치 여부에 똑같이 답해야 한다는 뜻이다. 대소문자를 구별하지 않는 문자열을 구현한 다음 클래스가 있다고 하자. public final class CaseInsensitiveString { private final String s; public CaseInsens..

    equals는 일반 규약을 지켜 재정의하라(1) - [3장. 모든 객체의 공통 메서드(아이템10)]

    꼭 필요한 경우가 아니면 equals를 재정의하지 말자. equlas 메서드는 재정의하기 쉬워 보이지만 곳곳에 함정이 도사리고 있어서 자칫하면 끔찍한 결과를 초래하기 때문이다. 이번 글에서는 'equals를 재정의 하지 않아도 되는 4가지 상황'과 '만약 equals 재정의를 해야 한다면, 만족해야 하는 5가지 규약'에 대해서 알아볼 것이다. 1. 재정의 하지 않아도 되는 4가지 상황 🚩 1. 각 인스턴스가 본질적으로 고유한 경우 🌴 싱글톤, ENUM 등 각 인스턴스가 본질적으로 고유한 경우 equals를 재정의 하지 않아도 된다. 2. 인스턴스의 '논리적 동치성(logical equality)'을 검사할 일이 없는 경우 🌴 설계자가 논리적 동치성 방식을 원하지 않거나 애초에 필요하지 않다고 판단하는 경..

    try-finally 보다는 try-with-resources를 사용하라 - [2장 객체 생성과 파괴(아이템9)]

    전통적으로 자원이 제대로 닫힘을 보장하는 수단으로 try-finally가 쓰였다. 하지만 아래의 2가지 문제점으로 인해 try-with-resources의 사용이 권장된다. 복수의 자원을 처리하게 되면 코드가 지저분해진다. 스택 추적 내역에 이전의 예외에 관한 정보는 남지 않게 되어, 실제 시스템에서의 디버깅을 몹시 어렵게 한다. try-with-resources의 장점들을 통해 해당 기능을 알아보자. 장점 1. 코드를 간결하게 작성할 수 있다. try-finally의 기본구조는 아래와 같다. static String firstLineOfFile(String path) throws IOException { BufferedReader br = new BufferedReader(new FileReader(p..

    실용주의 프로그래머

    "당신의 인생이다." 당신의, 당신이 사는, 당신이 만드는 인생이다. 1. 리뷰 🌵 이 책은 기술 서적이 아니다. 데이비드 토머스(David Thomas)와 앤드류 헌트(Andrew Hunt)의 오랜 성찰을 통해 정제한 지혜와 구체적인 실천법을 제공해주고 있다. 기술 서적이 아니라서 상대적으로 빠르게 읽을 수는 있지만, 내용을 이해하는 것에는 오히려 많은 시간이 필요한 책이다. 책을 끝까지 다 읽었지만, 나는 아직까지 책 내용의 15% 정도밖에 이해하지 못한 듯하다. 계속해서 프로그래머로써 일을 하면서 여러 가지 문제를 겪고 나서야 Aha Moment가 생길 듯싶다. 그래서 이 책을 두고두고 읽을 책이라고 말하고 싶다. 2. 책의 구성 🌴 책은 총 9개의 장으로 구성되어 있으며, 53개의 항목들로 구성되..

    finalizer와 cleaner 사용을 피하라 - [2장 객체 생성과 파괴(아이템8)]

    자바는 finalizer와 cleaner라는 두 가지 객체 소멸자를 제공한다. 하지만 여러 가지 문제점으로 인해 사용이 자제된다. 해당 글에서 문제점들과 적절한 쓰임새에 대해서 알아보자. 📢문제점 1. finalizer와 cleaner는 즉시 수행된다는 보장이 없다. finalizer나 cleaner를 얼마나 신속히 수행할지는 전적으로 가비지 컬렉터 알고리즘에 달렸으며, 이는 가비지 컬렉터 구현마다 천차만별이다. finalizer나 cleaner 수행 시점에 의존하는 프로그램의 동작 또한 마찬가지다. 📢문제점 2. finalizer와 cleaner는 실행되지 않을 수도 있다. 이는 접근할 수 없는 일부 객체에 딸린 종료 작업을 전혀 수행하지 못한 채 프로그램이 중단될 수도 있다는 얘기다. 따라서 프로그램..

    다 쓴 객체 참조를 해제하라 - [2장 객체 생성과 파괴(아이템7)]

    자바에서는 가비지 컬렉터가 메모리 관리를 도와준다. 하지만 가비지, 컬렉터가 있다고 해도 메모리 누수가 발생하지 않는 것은 아니다. 이번 글에서는 다 쓴 객체 참조를 해제하여 메모리 누수를 방지할 수 있는 3가지 상황을 알아보고자 한다. 1. Stack에서의 메모리 누수 & 해결책 public class Stack{ private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack(){ elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e){ ensureCapacity(); el..

    불필요한 객체 생성을 피하라 - [2장 객체 생성과 파괴(아이템6)]

    해당 장에서는 불필요하게 객체 생성을 하는 3가지 경우를 말해주고 있다. 하나씩 알아보자. 1. 문자열 public static void main(String[] args){ String hello1 = "hello"; String hello2 = new String("hello"); String hello3 = "hello"; System.out.println(hello1 == hello2); // false // 다른 인스턴스 System.out.println(hello1.equals(hello2)); // true // 같은 문자열 System.out.println(hello1 == hello3); // true // 같은 인스턴스 System.out.println(hello1.equals(hell..

    자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 - [2장 객체 생성과 파괴(아이템5)]

    아이템의 제목을 통해 '모든 경우에 의존 객체 주입을 사용해야겠다'라고 이해하지 않기를 바란다. 사용하는 자원에 따라 동작이 달라지는 클래스인 경우에 '의존 객체 주입'을 고려해보도록 하자. (앞으로 나올 예시에서도 확인할 수 있듯이 사전의 종류(Dictionary)에 따라 SpellChecker라는 클래스의 동작이 달라지는 경우에 의존 객체 주입을 사용하는 것을 알 수 있다.) public class SpellChecker{ private static final Dictionary dictionary = new Dictionary(); // 이것이 제목에서 나온 자원을 직접 명시하는 예시이다. private SpellChecker(){} public static boolean isValid(String..

    인스턴스화를 막으려거든 private 생성자를 사용하라 - [2장 객체 생성과 파괴(아이템4)]

    정적 메서드만 담은 유틸리티 클래스는 인스턴스로 만들어 쓰려고 설계한 클래스가 아니다. 하지만 생성자를 명시하지 않으면 컴파일러가 자동으로 기본 생성자를 만들어준다. 즉, 매개변수를 받지 않는 public 생성자가 만들어지며, 사용자는 이 생성자가 자동 생성된 것인지 구분할 수 없다. 그래서 이번 아이템을 통해 인스턴스 생성을 방지하는 방법을 알아보고자 한다. public abstract class UtilityClass{ // 원래는 기본생성자가 있지만, 출력을 통해 눈으로 확인하기 위해 아래와 같이 작성하였다. public UtilityClass(){ System.out.println("Contructor"): } } public class DefaultUtilityClass extends Utili..