본문 바로가기

Web Sever 개발과 CS 기초/자바

Lombok에 대한 이해와 기능

Lombok이 필요한 이유

자바는 최신의 개발 언어에 비해, 소스 코드가 복잡하고 길다. .

이러한 단점을 외부 라이브러리 Lombok을 통해 해결하였다.

예를 들어, 특정 클래스의 빌드패턴을 만들기 위해서는, 새로운 빌드클래스를 작성하는 번거로움이 있다.

그러나, 롬복을 사용하면 “@Builder” 어노테이션 하나로 대체할 수 있다.

  • 자바 애너테이션(Java Annotation)은 자바 소스 코드에 추가하여 사용할 수 있는 메타데이터(데이터를 모아둔 데이터)의 일종이다. 보통 @ 기호를 앞에 붙여서 사용한다” @Builder안에 많은 데이터가 함축되어 있다.

롬복에서 자주 사용되는 어노테이션을 통해 Lombok의 편리함을 알아보자.

@Builder

빌더 패턴의 역할을 한다.

import lombok.Builder;

@Builder

public class Dog {
    private int weight;
    private String color;
}

이렇게 간단하게 작성해도, 컴파일러가 받아들이는 소스코드.

public class Dog {
    private int weight;
    private String color;

    Dog(int weight, String color) {
        this.weight = weight;
        this.color = color;
    }

    public static DogBuilder builder() {
        return new DogBuilder();
    }

    public static class DogBuilder {
        private int weight;
        private String color;

        DogBuilder() {
        }

        public DogBuilder weight(int weight) {
            this.weight = weight;
            return this;
        }

        public DogBuilder color(String color) {
            this.color = color;
            return this;
        }

        public Dog build() {
            return new Dog(this.weight, this.color);
        }

        public String toString() {
            return "Dog.DogBuilder(weight=" + this.weight + ", color=" + this.color + ")";
        }
    }
}

사용 결과

public class Main {
    public static void main(String[] args) {
        Dog.DogBuilder dogBuilder = new Dog.DogBuilder();
        Dog dog1 = dogBuilder.color("빨간").weight(15).build();
        System.out.println(dog1.toString());
    }
}
Dog(weight=15, color=빨간)

@getter, setter

setter 클래스 빌드 변수 값을 설정하게 도와준다.

getter 설정된 빌드 변수 값을 불러오게 도와준다.

import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter

public class Dog {
    private int weight;
    private String color;
}

이렇게 간단하게 작성해도, 컴파일러가 받아들이는 소스코드.

public class Dog {
    private int weight;
    private String color;

    public Dog() {}

    public int getWeight() {
        return this.weight;
    }

    public String getColor() {
        return this.color;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

@Allargumentconstrutor

모든 필드 값을 설정하게 하는 생성자를 만들어준다.

import lombok.AllArgsConstructor;

@AllArgsConstructor

public class Dog {
    private int weight;
    private String color;
}

사용 결과

public class Main {
    public static void main(String[] args) {
        var dog = new Dog(15, "green");
        System.out.printf("%d  %s", dog.getWeight(), dog.getColor());
    }
}
15  green

@RequiredArfsConstructor

 final지정된 변수와 @Nonnull로 지정된 파리미터(변수)만 설정하는 생성자를 자동으로 만들어 준다.

@NoArgsConstructor

파라미터가 설정이 없는 생성자를 만들어 준다.

@Data

@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode.

기능을 모두 포함한다.

@ToString

객체가 가지는 변수 이름과 값을 가진, 문자열을 돌려준다.

+exclude로 설정한 변수는 문자열에서 제외한다.

import lombok.AllArgsConstructor;
import lombok.ToString;

@AllArgsConstructor
@ToString

public class Dog {
    private int weight;
    private String color;
}

사용 결과

public class Main {
    public static void main(String[] args) {
        var dog = new Dog(15, "green");
        System.out.println(dog.toString());
    }
}
Dog(weight=15, color=green)

@EqualsAndHashCode

@EqualsAndHashCode역할을 알아보기 위해서, Equals와 HashCode에 대해서 알아보자.

Equals

객체의 내용 즉 밸류 값을 비교한다.

반면에 == 연산자는 대상의 주소 값을 비교하여 true false값을 준다.

예를 들어

String str = new String(”가나다”);

str의 내용 값 밸류 값은 “가나다”이다

주소 값은 “가나가”가 아니라, 메모리 번호이다.

그래서

String str1 = new String(”가나다”)

String str2 = new String(”가나다”)

equals는 true이지만, ==는 false이다.

왜냐하면 서로 다른 객체이기 때문에 각자만의 주소값을 가진다.

이러한 주소값을 가지는 타입을 참조형 타입이라고 부른다.

반면에 int, char, boolean, byte 는 기본형 타입이다.

기본형 타입은 주소 값을 할당 받지 않고,

스택에 있는 값 자체를 그냥 선택한다.

int a = 3;

int b = 3;

a == b 는 참이 된다.

hashcode

해시코드란, 객체가 해시 알고리즘을 통해 얻게 되는, 정수 값을 의미한다.

만약 두 객체가 equals가 참이라면 해시 코드는 반드시 같다.

(equals가 참이라는 것은 내용물이 같다는 의미이니깐)

(다만 hashcode가 같다고 해도 equls인 것은 아니다. 다른 내용물이 해시코드를 거쳐서 같은 값이 나올 수 있으니깐)

 

그럼 해시 코드는 왜 필요한 것일까?

그것은 좋은 자료구조 해시를 만들기 위해서이다.

해시코드메소드와 equals메소드 둘 다 있어야 좋은 자료구조 해시를 만들 수 있다.

해시에 값을 저장하는 과정을 알아보면서, 그 이유를 알아보자.

먼저 해시에 넣으려는 값의 key값을 해시코드 메소드로 정수 값을 얻는다.

정수값을 바탕으로 값이 들어갈 위치 배열의 인덱스를 정한다.

그런데 이미 그 인덱스 안에 다른 값이 존재하는 상황이다 = 충돌 상황

이때 equals함수를 사용한다.

key값이 다르더라도, 해시 코드 값이 같은 경우도 있다. 그래서 equals메소드를 통해서

인덱스안에 이미 존재하는 값이 자신과 동일한 값인지 아니면, 해시코드만 같은 값인지 구분한다.

같은 값이라면, 덮어쓰기를 하고, 다른 값이 라면, 그 뒤에 이어붙이는 식으로

충돌 대비를 한 자료구조 해시를 완성한다.

@EqualsAndHashCode 사용

import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;

@EqualsAndHashCode
@AllArgsConstructor
public class Equals {
    private String id;
    private int password;
}

테스트

public class Main {

    public static void main(String[] args) {
        Equals a = new Equals("aa", 11);
        Equals b = new Equals("aa", 11);
        Equals c = new Equals("bb", 22);

        if (a.equals(b)) {
            System.out.println("true");
        } else {
            System.out.println("false");
        }
        if (a.equals(c)) {
            System.out.println("true");
        } else {
            System.out.println("false");
        }
        if (a == b) {
            System.out.println("같은 참조");
        } else {
            System.out.println("다른 참조");
        }
    }
}
true
false
다른 참조

Refence

https://gbsb.tistory.com/6

https://jisooo.tistory.com/entry/java-hashcode%EC%99%80-equals-%EB%A9%94%EC%84%9C%EB%93%9C%EB%8A%94-%EC%96%B8%EC%A0%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B3%A0-%EC%99%9C-%EC%82%AC%EC%9A%A9%ED%95%A0%EA%B9%8C