반응형

분류 전체보기 134

[item 11] equals를 재정의하려거든 hashCode도 재정의하라

equals를 재정의한 클래스 모두에서 hashCode도 재정의해야한다. 그렇지 않으면 hashCode 일반 규약을 어기게 되어 해당 클래스의 인스턴스를 HashMap이나 HashSet 같은 컬렉션의 원소로 사용할 때 문제를 일으킨다. [ Object 명세에서 발췌한 규약 ] 1. equals 비교에서 사용되는 정보가 변경되지 않았다면, 어플리케이션이 실행되는 동안 그 객체의 hashCode 메서드는 몇 번을 호출해도 일관되게 항상 같은 값을 반환해야 한다. 2. equals(Object)가 두 객체를 같다고 판단했다면, 두 객체의 hashCode는 똑같은 값을 반환해야 한다. 3. equals(Object)가 두 객체를 다르다고 판단했더라도, 두 객체의 hashCode가 서로 다른 값을 반환할 필요는 ..

[item 10] equals는 일반 규약을 지켜 재정의하라

equals메서드는 재정의하기 쉬워 보이지만 여러가지 함정이 있어서 자칫하면 끔찍한 결과를 초래한다. 다음에서 열거한 상황 중 하나에 해당한다면 재정의하지 않는 것이 좋다. [ equals를 재정의하지 않는 상황 ] 1. 각 인스턴스가 본질적으로 고유하다 - 동작하는 개체를 표현하는 클래스가 여기에 해당(Thread) 2. 인스턴스의 '논리적 동치성'을 검사할 일이 없다. 3. 상위 클래스에서 재정의한 equals가 하위 클래스에도 딱 들어맞는다. 4. 클래스가 private이거나 package-private이고 equals 메서드를 호출할 일이 없다. - 이를 회피하고 싶다면 아래와 같은 메서드를 구현해두자. @Override public boolean equals(Object o) { throw ne..

[item 6] 불필요한 객체 생성을 피하라

똑같은 기능의 객체를 매번생성하기보다는 객체 하나를 재사용하는 편이 나을 때가 많다. 다음 코드 중 첫번째는 절대 하지말아야 할 극단적인 예로 코드가 실행될 때마다 새로운 String 인스터스를 생성한다. 이를 개선한 버전이 두번째 코드다. 새로운 인스턴스를 만드는 대신 하나의 String 인스턴스를 사용한다. 나아가 이 방식을 사용한다면 같은 가상 머신 안에서 이와 똑같은 문자열 리터럴을 사용하는 모든 코드가 같은 객체를 재사용함이 보장된다. String s = new String("str"); String s = "str"; 생성자 대신 정적 팩터리 메서드를 제공하는 불변 클래스에서는 정적 팩터리 메서드를 사용해 불필요한 객체 생성을 피할 수 있다. 아래 첫번째 생성자는 호출할 때마다 새로운 객체를 ..

[item 3] private 생성자나 열거 타입으로 싱글턴임을 보증하라

✅ 싱글턴이란? 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말한다. 전형적인 예로는 함수와 같은 무상태 객체나 설계상 유일해야 하는 시스템 컴포넌트가 있다. ✅ 싱글턴 만드는 방식 [ public static final 필드 방식의 싱글턴 ] public class Elvis { public static final Elvis INSTANCE = new Elvis(); private Elvis() { ... } public void leaveTheBuilding() { ... } } private 생성자는 public static final 필드인 Elvis.INSTANCE를 초기화할 때 딱 한 번만 호출된다. 즉, public이나 protected 생성자가 없으므로 Elvis 클래스가 초기화될 때 ..

[Item 1] 생성자 대신 정적 팩토리 메서드.

클래스의 인스턴스를 얻는 일반적인 방법은 public 생성자다. 하지만, 이와 별도로 클래스는 정적 팩토리 메서드를 제공할 수 있다. 정적 팩토리 메서드란 객체 생성의 역할을 하는 클래스 메서드라는 의미를 갖고 있다. 아래 예시 코드를 참고하자면 java.time 패키지에 포함된 LocalTime 클래스의 정적 팩터리 메서드다. // LocalTime.class public static LocalTime of(int hour, int minute) { ChronoField.HOUR_OF_DAY.checkValidValue((long)hour); if (minute == 0) { return HOURS[hour]; } else { ChronoField.MINUTE_OF_HOUR.checkValidValue..

[Java] Json을 활용하는 구글의 오픈소스 Gson

✅ Gson이란? Json을 파싱하고, 생성하기 위해 구글에서 개발한 오픈소스로 데이터를 처리하는데 높은 수준의 유연성을 제공한다. 내부적으로 리플렉션(Reflection)을 사용하기 때문에 Map을 사용하여 Json을 파싱하는 것보다 가독성있는 코드를 작성할 수 있다. Spring Framework에 Gson을 적용하려면 의존성(dependency)를 추가해서 사용해야 한다. [ Maven 설정 ] com.google.code.gson gson 2.8.5 [ Gradle 설정 ] dependencies { implementation 'com.google.code.gson:gson:2.8.5' } ✅ Gson 활용하기 예제 코드를 통해 Java 객체와 Gson 라이브러리를 활용하여 Json을 파싱 및 생..

[Java] Optional이란? 개념과 사용법 - 1

✅ Optional이란? Optional 개념 및 사용법 자바로 프로그래밍 하다보면 정의되지 않은 객체에 대해 NULL값을 고려하게 되는 경우가 발생한다. 안정적인 실행을 위해서는 NULL값을 처리해 NPE(NullPointerException)가 발생하지 않게 체크해야 한다. 단순한 코드라면 짧은 로직으로 처리할 수 있지만, 스케일이 커질 수록 고려해야할 변수가 많아지고, 그만큼 NULL 체크 로직이 길어지게 된다. 이러한 상황을 위해 Java8에서는 Optional 클래스를 도입하여 NPE를 방지할 수 있도록 도와준다. Optional는 NULL이 올 수 있는 값을 감싸는 Wrapper 클래스로, NPE가 발생하지 않도록 도와준다. Optional 클래스는 아래 예제처럼 value에 값을 저장하기 때..

[Design Pattern] 컴포지트 패턴(Composite Pattern)이란

✅ 컴포지트 패턴이란? 컴포지트 패턴이란, 클라이언트가 복합 객체나 단일 객체를 동일하게 취급하는 것을 목적으로 한다. 특히 컴포지트(Composite)의 의도는 트리 구조로 작성하며, 전체-부분 관계를 표현하는 것으로 전체와 부분은 동일한 인터페이스를 사용할 수 있다. [ 해당 패턴을 사용하는 경우 ] 1. 복합 객체와 단일 객체의 처리 방법이 동일한 경우, 전체-부분 관계를 정의할 수 있다. 2. 객체들 간에 계급 및 계층 구조가 있고 이를 표현해야 할 경우, 3. 대표적으로 Directory-File 관계가 존재한다. [ 구조 ] Component Leaf와 Composite가 구현해야하는 Interface로, Leaf와 Composite는 모두 Component라는 같은 타입으로 다뤄 진다. Le..

[Design Pattern] 템플릿 메서드 패턴(Template Method Pattern)이란

✅ 템플릿 메서드 패턴이란? 템플릿 메서드 패턴이란 특정 작업을 처리하는 일부분을 서브 클래스로 캡슐화하여 전체적인 구조는 바꾸지 않고, 특정 단계에서 수행하는 내용을 바꾸는 패턴이다. 즉, 동일한 기능을 상위 클래스에서 정의하면서 확장/수정이 필요한 부분만 서브 클래스에서 오버라이딩으로 구현하도록 만든다. 예를 들어, 전체 로직은 상위 클래스에서 구현하고, 나머지 부분은 하위 클래스에서 구현하도록 만들어서 코드의 재사용성을 높이는 것이다. [ 구조 ] [ 장단점 ] 장점 1. 코드의 재사용성을 높여 중복 코드를 줄일 수 있다. 2. 하위 클래스의 역할을 줄여 핵심 로직의 관리가 용이하다. 3. 객체지향적으로 코드를 구성할 수 있다. 단점 1. 추상 메서드가 많아지면서 클래스 관리가 복잡해진다. [ 예제..

[Java] 제네릭(generic)이란?

✅ Generic 자바에서 제네릭(generic)이란, 데이터의 타입을 일반화(generalize)한다는 것을 의미한다. 쉽게 설명하자면 '데이터 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있도록 일반화하는 방법'이다. 이렇게 컴파일 시에 미리 타입 검사를 수행하면 다음과 같은 장점이 있다. 1. 클래스나 메서드 내부에서 사용되는 객체의 타입 안정성을 높일 수 있다. 2. 반환값에 대해 타입 변환 및 타입 검사에 들어가는 노력을 줄일 수 있다. JDK 1.5 이전에서는 여러 타입을 사용하는 대부분의 클래스나 메서드에서 인수나 반환값으로 Object 타입을 사용해왔다. 하지만 반환된 Object 객체를 다시 원하는 타입으로 변환해야 하며, 이러한 상황에서 오류가 발생할 가능성도..

반응형