@Data

cy8erpsycho·2023년 8월 28일
0

스프링

목록 보기
14/29
post-thumbnail

스프링에서 toString() 등을 자동으로 생성하도록 @Data 어노테이션을 이용한다.

@Data 어노테이션은 Lombok 라이브러리에서 제공하는 어노테이션입니다. 이 어노테이션은 자바 클래스 위에 붙여서 사용할 수 있으며, getter, setter, equals(), hashCode(), toString() 등의 표준 메소드를 자동으로 생성해 줍니다.

예를 들어, 다음과 같은 간단한 클래스가 있을 때:

public class Person {
    private String name;
    private int age;
}

@Data 어노테이션을 사용하여 다음과 같이 간소화할 수 있습니다:

import lombok.Data;

@Data
public class Person {
    private String name;
    private int age;
}

이렇게 하면 Person 클래스의 객체는 getName(), setName(String name), getAge(), setAge(int age), equals(Object o), hashCode(), toString() 등의 메소드를 자동으로 갖게 됩니다.


toString()메소드를 자동으로 갖게 되면 얻는 장점

toString() 메소드를 자동으로 구현하게 되면 여러 가지 장점이 있습니다:

  1. 코드 간결성: 클래스에 필요한 표준 메소드를 직접 작성하지 않아도 되므로 코드가 간결해집니다. 이로 인해 개발 시간이 단축되고 유지 보수도 쉬워집니다.

  2. 디버깅 용이성: 객체의 상태를 쉽게 출력할 수 있어 디버깅이 더 쉬워집니다. 로그나 콘솔 출력에서 객체의 현재 상태를 빠르게 확인할 수 있습니다.

  3. 일관성: 자동으로 생성된 toString() 메소드는 일관된 형식을 갖게 됩니다. 이로 인해 코드 전체에서 객체의 문자열 표현을 일관되게 관리할 수 있습니다.

  4. 데이터 확인: 테스트 중이거나 실제 환경에서 데이터의 정확성을 빠르게 확인하고 싶을 때 유용합니다.

  5. 문서화: 자동 생성된 toString() 메소드는 종종 개발 문서나 API 문서에서도 유용하게 사용됩니다.

  6. 에러 추적: 에러가 발생했을 때, 로그에 기록되는 객체의 toString() 출력은 문제 해결에 유용한 정보를 제공할 수 있습니다.

  7. 코드 리뷰 및 협업 효율성: 자동으로 생성된 코드는 일반적으로 잘 알려진 패턴을 따르므로, 코드 리뷰어나 팀원들이 더 쉽게 코드를 이해할 수 있습니다.

그러나 모든 상황에 toString()의 자동 생성이 유용한 것은 아닙니다. 예를 들어, 객체가 너무 많은 정보를 가지고 있거나 중첩된 구조를 가지고 있을 경우, 자동 생성된 toString() 메소드가 너무 많은 정보를 출력할 수 있습니다. 또는 보안상 중요한 정보를 가진 객체의 경우, toString() 메소드로 인해 중요 정보가 노출될 위험이 있습니다. 이러한 경우에는 직접 toString() 메소드를 구현하여 필요한 정보만을 출력하도록 할 수 있습니다.


toString()

toString() 메소드가 자동으로 생성되면, 일반적으로 필드의 이름과 그에 해당하는 값을 쌍으로 출력합니다. 예를 들어, 위에서 언급한 Person 클래스에 대한 toString() 메소드의 출력은 아마도 다음과 같을 것입니다:

Person{name='John', age=30}

이러한 출력은 자동으로 생성된 toString() 메소드에 의해 만들어집니다.

이를 실제 코드로 확인해보면 다음과 같이 작성할 수 있습니다:

import lombok.Data;

@Data
public class Person {
    private String name;
    private int age;

    public static void main(String[] args) {
        Person person = new Person();
        person.setName("John");
        person.setAge(30);
        
        System.out.println(person.toString());  // 출력: Person{name='John', age=30}
    }
}

이 예시에서 Person 객체를 생성하고, 이름과 나이를 설정한 후에 toString() 메소드를 호출하여 콘솔에 출력하고 있습니다. 결과적으로 Person{name='John', age=30} 이라는 문자열이 출력될 것입니다.

이렇게 toString() 메소드가 있으면, 객체의 현재 상태를 쉽게 확인할 수 있습니다. 이는 디버깅이나 로깅, 데이터 검증 등에서 매우 유용합니다.


System.out.println(person); 과 System.out.println(person.toString);

System.out.println(person); 이렇게 작성해도 완전히 괜찮습니다. 실제로 Java에서 System.out.println(Object obj) 메소드는 내부적으로 ObjecttoString() 메소드를 호출합니다. 따라서 위의 예에서 System.out.println(person.toString());System.out.println(person);는 같은 출력 결과를 가져올 것입니다.

다음 두 줄은 사실상 동일하게 동작합니다:

System.out.println(person.toString());
System.out.println(person);

@Data 어노테이션 덕분에 자동 생성된 toString() 메소드가 있으므로, System.out.println(person);을 호출하면 Person 객체의 toString() 메소드가 자동으로 호출되어 적절한 문자열 표현이 출력됩니다. 이는 디버깅이나 로깅을 할 때 매우 유용합니다.


만약 person에 @Data를 쓰지 않는다면?

@Data 어노테이션을 사용하지 않고 System.out.println(person);을 호출하면, Person 클래스가 명시적으로 toString() 메소드를 오버라이딩하지 않았다면, Object 클래스의 기본 toString() 구현이 사용됩니다.

Object 클래스의 기본 toString() 메소드는 객체의 클래스 이름과 해시 코드를 16진수 문자열로 반환합니다. 이 형식은 일반적으로 다음과 같습니다:

[클래스명]@[해시코드의 16진수 표현]

예를 들어, 아래와 같은 Person 클래스가 있다고 가정해 보겠습니다.

public class Person {
    private String name;
    private int age;

    // ... (getter, setter 등은 생략)
}

이렇게 @Data 어노테이션을 사용하지 않았다면, System.out.println(person);의 출력은 다음과 유사하게 나타날 것입니다:

Person@7a81197d

이 출력에서 Person은 클래스 이름이고, 7a81197d는 해당 객체의 해시 코드의 16진수 표현입니다 (해시 코드는 실행할 때마다 달라질 수 있습니다).

이러한 기본 toString() 출력은 객체를 구분하기 위한 기본적인 정보만을 제공하므로, 일반적으로 디버깅이나 로깅에는 그다지 유용하지 않습니다. 이 경우에는 개발자가 명시적으로 toString() 메소드를 오버라이딩하여 더 유용한 정보를 출력하도록 구현할 필요가 있습니다.


오버라이딩

Java에서 toString() 메소드를 오버라이딩하는 방법은 매우 간단합니다. @Override 어노테이션을 사용하여 Object 클래스의 toString() 메소드를 오버라이딩하면 됩니다.

예를 들어, Person 클래스의 nameage 필드 값을 출력하려면 다음과 같이 작성할 수 있습니다:

public class Person {
    private String name;
    private int age;

    // getter, setter 등 다른 코드는 생략

    @Override
    public String toString() {
        return "Person{" +
               "name='" + name + '\'' +
               ", age=" + age +
               '}';
    }
}

이렇게 하면, System.out.println(person);을 호출했을 때 출력되는 문자열은 다음과 같을 것입니다:

Person{name='John', age=30}

여기서는 문자열 연산을 간단하게 하기 위해 문자열 덧셈을 사용했습니다만, 성능이 중요한 상황에서는 StringBuilderStringBuffer를 사용하는 것이 더 효율적일 수 있습니다.

toString() 메소드를 오버라이딩할 때는 보통 객체의 중요한 정보나 상태를 반영하는 필드 값을 출력하도록 구현합니다. 이렇게 하면 디버깅이나 로깅, 또는 객체 상태의 시각적 표현을 쉽게 할 수 있습니다.

@Data 을 쓸 때의 다음의 코드의 내부 구현

@Override
public String toString() {
    return "Person{" +
           "name='" + name + '\'' +
           ", age=" + age +
           '}';
}

@Data 어노테이션을 사용하면 Lombok 라이브러리가 내부적으로 toString() 메소드를 자동으로 생성해줍니다. 생성되는 코드는 실제로 바이트코드 수준에서 추가되므로 소스 코드에는 직접 보이지 않습니다. 하지만 toString() 메소드의 동작은 위에서 수동으로 오버라이딩한 것과 유사하게 작동합니다.

즉, Lombok의 @Data 어노테이션을 사용하면 위와 같은 toString() 메소드를 소스 코드에 명시적으로 작성하지 않아도, 동일한 기능을 하는 toString() 메소드가 내부적으로 생성됩니다. 이렇게 생성된 toString() 메소드는 객체의 모든 필드를 문자열로 변환하여 출력하는 형태로 동작하게 됩니다.

따라서 @Data 어노테이션을 사용하면, toString()을 포함한 여러 표준 Java 메소드 (equals(), hashCode(), getter, setter 등)를 자동으로 생성할 수 있어 코드의 간결성과 가독성을 높일 수 있습니다.

https://chat.openai.com/share/037c97d3-afbb-48f9-8b98-699328490739

0개의 댓글