Language
-
[Effective Java] 아이템11: equals를 재정의하려거든 hashCode도 재정의하라Language/Java 2022. 6. 5. 00:11
equals를 재정의한 클래스 모두에서 hashCode도 재정의해야 한다. 그렇지 않으면 hashCode 일반 규약을 어기게 되어 해당 클래스의 인스턴스를 HashMap이나 HashSet 과 같은 컬렉션의 원소로 사용할 때 문제를 일으킬 것이다. ✔️ hashCode 에 관한 규약 다음은 Object 명세에서 발췌한 규약이다. equals 비교에 사용되는 정보가 변경되지 않았다면, 애플리케이션이 실행되는 동안 그 객체의 hashCode 메서드는 몇 번을 호출해도 일관되게 항상 같은 값을 반환해야 한다. 단 애플리케이션을 다시 실행한다면 이 값은 달라져도 상관없다. equals(Object)가 두 객체를 같다고 판단했다면, 두 객체의 hashCode는 똑같은 값을 반환해야 한다. equals(Object)..
-
[Effective Java] 아이템10: equals는 일반 규약을 지켜 재정의하라Language/Java 2022. 6. 4. 16:53
equals 메서드는 재정의하기 쉬워 보이지만 곳곳에 함정이 도사리고 있다. 따라서 재정의가 필요하지 않은 경우에는 재정의하지 않는 것이 최선의 선택이다. ✔️ equals를 재정의하지 않는 것이 좋은 상황 1️⃣ 각 인스턴스가 본질적으로 고유한 경우 값을 표현하는 게 아니라 동작하는 개체를 표현하는 클래스. Thread 와 같은 클래스가 좋은 예시다. 2️⃣ 인스턴스의 '논리적 동치성'을 검사할 일이 없는 경우 3️⃣ 상위 클래스에서 재정의한 equals가 하위 클래스에도 딱 들어맞는 경우 4️⃣ 클래스가 private 이거나 package-private 이고, equals 메서드를 호출할 일이 없는 경우 참고❗️ equals가 실수로라도 호출되는 걸 막고 싶다면 다음처럼 구현하자. @Override ..
-
[Effective Java] 아이템9: try-finally 보다는 try-with-resources 를 사용하라Language/Java 2022. 5. 30. 01:19
자바에는 InputStream, OutputStream, java.sql.Connection과 같이 close 메서드를 호출해 직접 닫아줘야 하는 자원이 많다. 그런데 자원 닫기는 클라이언트가 놓치기 쉬워 성능 문제로 이어질 수 있다. 그렇다면 자원이 제대로 닫히도록 보장할 수 있는 방법은 무엇일까? 전통적으로 자원이 제대로 닫힘을 보장하는 수단으로 try-finally가 쓰였다. ✔️ try-finally static String firstLineOfFile(String path) throws IOException { BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { br..
-
[Effective Java] 아이템8: finalizer와 cleaner 사용을 피하라Language/Java 2022. 5. 30. 00:39
자바는 두 가지 객체 소멸자를 제공한다. 1️⃣ 첫 번째는 finalizer 다. finalizer는 예측할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요하다. 2️⃣ 두 번째는 cleaner 다. finalizer는 오동작, 낮은 성능, 이식성 문제가 있었기 때문에, 자바 9에서 deprecated API로 지정되었고 finalizer의 대안으로 cleaner가 소개되었다. cleaner는 finalizer보다는 덜 위험하지만, 여전히 예측할 수 없고, 성능이 느리고, 일반적으로 불필요하다. 그렇다면 지금부터 finalizer와 cleaner의 문제점을 알아보자. ✔️ 불확실성 (수행 미보장) finalizer와 cleaner는 즉시 수행된다는 보장이 없다. 객체에 접근할 수 없게 된 후 f..
-
[Effective Java] 아이템7: 다 쓴 객체 참조를 해제하라Language/Java 2022. 5. 21. 03:21
가비지 컬렉션 언어에서는 메모리 누수를 찾기가 아주 까다롭다. 가비지 컬렉터는 객체 참조 하나를 살려두면 그 객체 뿐만 아니라 그 객체가 참조하는 모든 객체(그리고 또 그 객체들이 참조하는 모든 객체...)를 회수해가지 못한다. 그래서 단 몇 개의 객체가 매우 많은 객체를 회수되지 못하게 할 수 있고, 잠재적으로 성능에 악영향을 줄 수 있다. 스택을 구현하는 다음의 코드를 보자. 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_CAP..
-
[Effective Java] 아이템6: 불필요한 객체 생성을 피하라Language/Java 2022. 5. 21. 02:16
똑같은 기능의 객체를 매번 생성하기보다는 객체 하나를 재사용하는 편이 나을 때가 많다. ✔️ String 인스턴스 String s = new String("bikini"); // 1, 따라하지 말 것! String s = "bikini"; // 2 1번 코드의 경우, 실행될 때마다 String 인스턴스를 새로 만든다. 생성자에 넘겨진 "bikini" 자체가 이 생성자가 만들어내는 String과 기능적으로 완전히 똑같으므로, 완전히 쓸데없는 행위이다. 2번 코드는 1번 코드를 개선한 것이다. 새로운 인스턴스를 매번 만드는 대신에 하나의 String 인스턴스를 사용한다. 이 방식은 같은 가상 머신 안에서 똑같은 문자열 리터럴을 사용하는 모든 코드가 같은 객체를 사용함이 보장된다. ✔️ 불변 클래스의 정적 팩..
-
[Effective Java] 아이템5: 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라Language/Java 2022. 5. 21. 00:24
많은 클래스가 하나 이상의 자원에 의존한다. 이런 클래스는 정적 유틸리티 클래스로 구현하거나 싱글턴으로 구현할 수 있는데, 둘 다 그리 좋지 않은 방법이다. 다음의 예시를 보자. // 정적 유틸리티 public calss SpellChecker { private static final Lexicon dictionary = ...; private SpellChecker() {} // 객체 생성 방지 public static boolean isValid(String word) {...} public static List suggestions(String typo) {...} } // 싱글턴 public calss SpellChecker { private static final Lexicon dictionar..
-
[Effective Java] 아이템4: 인스턴스화를 막으려거든 private 생성자를 사용하라Language/Java 2022. 5. 14. 02:17
이따금 단순히 정적 메서드와 정적 필드만을 담은 클래스를 만들고 싶을 때가 있을 것이다. 이렇게 정적 멤버만 담은 클래스는 인스턴스로 만들어 쓰려고 설계한 것이 아니다. 따라서 이러한 클래스의 인스턴스화를 막아야하는데, 생성자를 명시하지 않으면 컴파일러가 자동으로 기본 생성자를 만들어준다는 문제가 있다. 그렇다면 어떻게 클래스의 인스턴스화를 막을 수 있을까? 그 방법은 private 생성자를 추가하는 것이다. 다음의 코드를 참고하자. public class UtilityClass { // 기본 생성자가 만들어지는 것을 막는다 (인스턴스화 방지용) private UtilityClass() { throw new AssertionError(); } ... // 나머지 코드는 생략 } 이렇게 구현하면, 명시적 ..