본문 바로가기

Effective Java

equals 를 재정의하려거든 hashCode 도 재정의하라 hashCode 는 equals 를 재정의할 때 같이 재정의 해줘야 한다. 그 이유는 hashCode를 사용하는 HashSet, HashMap 같은 컬랙션의 원소로 사용할 때 문제를 일으킨다.hashCode 를 재정의할 때 주의점은 크게 3가지 있다. equals 비교에 사용되는 정보가 변경되지 않았다면, hashCode 메서드는 항상 같은 값을 반환해야 한다. equlas 가 두 객체를 같다고 판단했다면, 두 객체의 hashCode 는 같아야 한다. equlas 가 두 객체를 다르다고 판단했더라도, 두 객체의 hashCode 가 서로 다른 값을 반환할 필요는 없다. 더보기
equals는 일반 규약을 지켜 재정의하라 모든 클래스는 Object 클래스를 상속하고 있다. Object 클래스를 상속 함으로 Object 가 제공하는 메서드를 사용하거나 재정의(overriding)할 수 있다.Object가 제공하는 메서드의 예로는 equals, hashcode, clone, toString, finalize 가 있다. 이 중에서 equals는 객체, 값과 비교할 때 쓰인다. equals를 재정의(overriding)을 하지 않으면 객체를 비교할 때는 주소 즉 물리적 동치성(==)을 비교하게 된다. 쉽게 말하자면 객체가 가지고 있는 필드 값이 같더라도 똑같은 객체가 아니기 때문에 물리적 동치성은 같지 않다. public class AA { private final String a; public AA(String a) { thi.. 더보기
try-finally 보다는 try-with-resources를 사용하라 try-finally는 평소에 사용하지 않고 try-catch-finally를 주로 사용했다. 그 이유는 try-finally를 사용하면 catch 구문으로 예외처리를 못하고 무조건 throw를 사용해서 외부로 예외를 보내게 된다. public static void main(String[] args) throws IllegalAccessException { try { throw new IllegalAccessException(); }finally { System.out.println("실행1"); } System.out.println("실행2"); } 위의 코드는 컴파일 단계에서 에러가 난다. 이유는 catch 문으로 에러를 처리하고 있지 않기 때문에 try 코드 밖에 있는 실행 2는 절대로 실행될 수가.. 더보기
finalizer와 cleaner 사용을 피하라 자바에는 finalizer, cleaner 두 개의 객체 소멸자를 제공한다. finalizer는 모든 클래스가 override(재정의) 할 수 있다. @Override protected void finalize() throws Throwable { super.finalize(); } finalizer은 자바 9에서는 사용 자제 API로 지정했다. 사용 자제로 설정한 이유는 크게 3가지 있다. 1.finalize는 가비지 컬렉션이 객체 메모리를 정리 한 후에 실행이 될 수도 있고 안 될 수도 있다. 이 말은 실행 시점뿐 아니라 실행 여부조차 보장하지 않는다. 2.속도 측면에서 느려진다. 3.finalizer 공격에 노출되어 심각한 보안 문제를 일으킬 수도 있다. finalizer 공격이란? finalize.. 더보기
불필요한 객체 생성을 피하라 똑같은 기능의 객체를 매번 생성하기보다는 객체 하나를 재사용하는 편이 나을 때가 많다. 1. 예를 들면 String 객체를 만드는 방법은 두 가지가 있다. 첫 번째는 생성자를 통해서 만드는 것이다. String str = new String("str"); 두 번째 방법은 새로운 인스턴스를 매번 만드는 게 아니라 하나의 인스턴스를 재사용하는 방법이다. String str = "str"; 처음에는 두 개의 코드를 보고 같다고 생각할 수 있다. 하지만 두 코드 사이에는 큰 차이가 있다. 코드 예시를 보자. String str = new String("str"); String str1 = new String("str"); //처음 출력 System.out.println(str == str1); String ss.. 더보기
자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 클래스를 생성할 때 클래스 내부에서 다른 클래스를 의존하는 경우가 있다. 이런 경우에는 정적 팩토리 패턴, 싱글턴 패턴을 사용하지 말고 인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식을 선택해야 한다. Trip이라는 인터페이스가 있고 Trip을 구현하는 JapanTrip, AmericaTrip이라는 클래스가 존재한다. public interface Trip { public String TripTitle(); public Date TripDate(); } public class JapanTrip implements Trip{ @Override public String TripTitle() { return "Japan"; } @Override public Date TripDate() { retur.. 더보기
인스턴스화를 막으려거든 private 생성자를 사용하라 단순히 정적 메서드와 정적 필드만을 담은 클래스를 만들고 싶을 때가 있을 것이다. 그럴 때 생성자를 public이 아닌 private을 사용해서 인스턴스를 만드는 것을 제한하여 사용하면 된다. 예를 들면 java.lang.Math, java.util.Arrays, java.util.Collections가 있다. public class Test { private Test() { throw new AssertionError(); } } 더보기
private 생성자나 열거 타입으로 싱글턴임을 보증하라 싱글턴이란 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말한다. 싱글턴의 전형적인 예로는 무상태 객체, 설계상 유일해야 하는 시스템 컴포넌트를 들 수 있다. 그런데 클래스를 싱글턴으로 만들면 이를 사용하는 클라이언트를 테스트하기가 어려워질 수 있다. 싱글턴을 만드는 방법은 3가지가 있다. 첫 번째 방법은 생성자를 private으로 설정을 하고 static final로 설정한 필드를 제공하는 방법이다. static을 사용함으로써 인스턴스를 생성하지 않고 사용할 수 있고 final을 사용함으로써 필드값을 다시 설정하는 것을 막을 수 있다. public class Single { public static final Single INSTANCE = new Single(); private Single() { .. 더보기