Red Glitter Pointer

 

Java에서 문자열 앞 뒤의 공백을 제거하기 위한 메소드가 2가지가 있다

trim() 과 strip() 이 있는데, 이 두가지의 차이점을 알아볼 예정이다! 

 

 

 

1. trim()

코드 👇

// 앞 뒤로 공백이 있는 문자열
String str = "  안녕하세여~~  ";

// 공백 제거
String trimStr = str.trim();

System.out.println("원본 문자열: '" + str + "'");
System.out.println("trim 문자열: " + trimStr);

 

결과 👇

원본 문자열: '  안녕하세여~~  '
trim 문자열: 안녕하세여~~

 

 

 

 

2. strip()

코드 👇

// 앞 뒤로 공백이 있는 문자열
String str = "  안녕하세여~~  ";

// 공백 제거
String stripStr = str.strip();

System.out.println("원본 문자열: '" + str + "'");
System.out.println("strip 문자열: " + stripStr);

 

결과 👇

원본 문자열: '  안녕하세여~~  '
strip 문자열: 안녕하세여~~

 

strip() 메소드는 Java 11 이후 새롭게 추가된 메소드이다.

strip()과 trim() 메소는 둘 다 문자열 앞 뒤 공백을 모두 제거해준다.

 

 

3. stripLeading(), stripTrailing()

코드 👇

// 앞 뒤로 공백이 있는 문자열
String str = "  안녕하세여~~  ";

// 공백 제거
String stripLeadingStr = str.stripLeading();
String stripTrailingStr = str.stripTrailing();


System.out.println("원본 문자열: '" + str + "'");
System.out.println("stripLeading 문자열: '" + stripLeadingStr + "'");
System.out.println("stripTrailing 문자열: '" + stripTrailingStr + "'");

 

결과 👇

원본 문자열: '  안녕하세여~~  '
stripLeading 문자열: '안녕하세여~~  '
stripTrailing 문자열: '  안녕하세여~~'

 

Java11 이후로는 stripLeading(), stripTrailing()도 사용 가능하다

stripLeading() : 문자열 앞의 공백 제거

stripTrailing() : 문자열 뒤의 공백 제거

 

 

 

 

 

trim() vs strip() 차이

이렇게 보면 차이가 없어보이지만, 제거하는 공백의 종류가 다르다.

 

 

trim() : '\u0020' 이하의 공백들만 제거

strip() : 유니코드의 공백들을 모두 제거

 

유니코드에는 스페이스('\u0020'), 탭('\u0009) 외에도 더 많은 종류의 공백 문자들이 있다.

strip() 메소드는 trim()보다 더 많은 종류의 공백을 제거할 수 있음!

따라서 공백 제거를 위해 사용한다면, Java11 버전 이후로는 strip()을 사용하는게 좋을 듯

 

 

 

데이터베이스에서 데이터를 식별하기 위해 PK를 통해 데이터를 식별하게 된다. PK를 숫자로 지정해 둔 경우, 데이터베이스에 대한 공격에 취약한 경우가 있기 때문에 url에 PK값을 노출하는 방식은 좋지 않다고 한다. 

이를 보완하기 위해 UUID를 사용하는 방법이 있다!

UUID는 32개의 문자와 4개의 하이픈으로 구성된 문자열이며 8-4-4-4-12 개의 문자열로 이루어져 있으며 5가지 버전을 가지고 있다.

 

 

 

 UUID(Universally Unique Identifier)의 정의 및 구조

 

 

 1. UUID의 정의

💡 UUID(Universally Unique Identifier)란?

범용 고유 식발자를 의미하며 중복이 되지 않는 유일한 값을 구성하고자 할 때 주로 사용되는 고유 식별자이다.
주로 세션 식별자, 쿠키 값, 무작위 데이터베이스 키 등에 사용된다.

 

 

 

 

 2. UUID 구조

💡 UUID는 16바이트(128비트) 형태의 구조를 가짐.
하나의 UUID 길이는 36자리이며 4개의 하이픈과 32개의 16진수 문자열로 구성되어있음 !
구조 길이 내용
time_low 4 / 8 (8자리) 시간의 low 32비트를 부여하는 정수
time_mid 2 / 4 (4자리) 시간의 middle 16비트를 부여하는 정수
time_hi_and_version 2 / 4 (4자리) 최상위 비트에서 4비트 version, 그리고 시간의 high 12비트
clock_seq_hi_and_res_clock_seq_low 2 / 4 (4자리) 최상위 비트에서 1-3비트는 UUID의 레이아웃형식, 그리고 13-15비트 클럭 시퀀스
node 6 / 12 (12자리) 48비트 노드 id

 

 

🤔 중복된 UUID가 생길 가능성이 있을까?

랜덤된 값을 생성한다는 UUID는 이론상으로는 중복값이 생성될 가능성이 존재한다. 하지만 UUID의 총 생성 가능 개수는  340,282,366,920,938,463,463,374,607,431,768,211,456개로 중복된 값이 생길 확률을 계산해보면 초당 10억개의 UUID를 100년동안 생성했을 시 중복된 값이 생길 확률이 50%이기 때문에... 중복된 값은 걱정하지 않아도 될 것 같다.ㅎㅎ

 

 

 

 

 3. UUID의 버전

버전 설명 특징
UUID Version1 현재 시간 + 랜덤한 MAC 주소 유일성 보장됨
보안에 취약
UUID Version2 버전 1과 유사하지만, 시퀀스 번호 대신 POSIX UID(사용자 ID) 사용 현재는 거의 사용되지 않는다
UUID Version3 해시 함수인 MD5 해시를 기반으로 이름과 네임스페이스에 대한 조합 암호화 해시 함수를 사용하여 생산하므로 보안성 높다
이름과 네임스페이스가 같다면 같은 UUID가 생성
UUID Version4 랜덤한 값 보안성이 높고 생성속도가 빠르다
UUID Version5 버전 3과 유사하지만, SHA-1 해시 사용 보안에 취약하다는 단점..

 

 

아래에서는 자주 사용되는 Version1과 Version4에 대해서만 글을 작성해볼 예정이다.! 

 

UUID version 1

 

 

💡해당 버전은 MAC 주소와 타임스탬프(현재 시간)을 기반으로 UUID를 생성해준다.
동시간대에 생성했을 때 앞의 8자리 문자열만 바뀌는 것을 확인할 수 있음. 각자 다른 컴퓨터가 같은 시간대에 UUID를 생성할 경우 MAC주소가 다르기 때문에 앞의 8자리 문자외 다른 문자 또한 다른 UUID가 생성될 것이다! 

⚠️ 단점 : 유일성이 보장되지만, 보안에 취약함
import java.util.UUID;

/**
 * [MAC Address] MAC 주소 대신에 임의의 48비트 숫자를 생성합니다.(보안 우려로 이를 대체합니다)
 * @return
 */
private static long get64LeastSignificantBitsForVersion1() {
    Random random = new Random();
    long random63BitLong = random.nextLong() & 0x3FFFFFFFFFFFFFFFL;
    long variant3BitFlag = 0x8000000000000000L;
    return random63BitLong | variant3BitFlag;
}

/*
 * [TimeStamp] 타임스템프를 이용하여 64개의 최상위 비트를 생성합니다.
 */
private static long get64MostSignificantBitsForVersion1() {
    final long currentTimeMillis = System.currentTimeMillis();
    final long time_low = (currentTimeMillis & 0x0000_0000_FFFF_FFFFL) << 32;
    final long time_mid = ((currentTimeMillis >> 32) & 0xFFFF) << 16;
    final long version = 1 << 12;
    final long time_hi = ((currentTimeMillis >> 48) & 0x0FFF);
    return time_low | time_mid | version | time_hi;
}

/**
 * UUID v1을 생성하여 반환합니다.(MAC Address, TimeStamp 조합)
 *
 * @return
 */
public static UUID generateType1UUID() {
    long most64SigBits = get64MostSignificantBitsForVersion1();
    long least64SigBits = get64LeastSignificantBitsForVersion1();
    return new UUID(most64SigBits, least64SigBits); // 62dd98f0-bd8e-11ed-93ab-325096b39f47
}

 

📖 MAC Address (Media Access Control) 이란?

네트워크 인터페이스를 식별하기 위한 고유한 주소. 전 세계에서 유일하며, 일반적으로 12자리 16진수로 나타낸다!

 

 

 

 

UUID version 4

 

💡 보안 난수 생성기를 이용해 모두 다른 ID가 생성된다. 중간에 숫자 4가 고정적으로 박혀있는 것을 볼 수 있는데 이는 버전을 나타내기 위한 표시임. 

🌟 보안성이 높고 생성 속도가 빠르다는 장점을 가지고 있어 대중적으로 많이 사용되는 UUID 버전이다!

 

import java.util.UUID;

// 버전 4 UUID 생성하기
UUID uuid4 = UUID.randomUUID();
System.out.println("Version 4 UUID: " + uuid4); // Version 4 UUID: c48b2aef-9d79-44fe-bd97-46fd31361069

 

 

 

 

 4. 데이터베이스에 UUID를 도입했을 때 장점

1. 보안

유저 삭제, 게시글 삭제 등의 API를 호출할 때 데이터베이스에 존재하는 PK값을 가지고 클라이언트가 API서버로 호출을 하게 된다. 이때 PK가 숫자로 되어 있을 경우 다른 유저나 게시글의 PK를 유추해 접근을 시도 할 수 있다.

하지만 UUID를 사용했을 경우 모든 PK는 유추가 불가능 하기 때문에 보안상에서 안전하다.

 

 

2. 연관관계의 데이터를 입력할 때 

연관관계의 데이터를 같이 입력하게 된다면, 데이터 베이스에 저장된 PK의 값을 가지고 FK를 지정해서 입력해 줘야한다. ORM을 쓸경우 ORM이 알아서 맵핑해 주지만, ORM을 쓰지 못할 경우엔 입력된 데이터를 가지고 FK를 지정 해 줘야하는데, UUID를 사용할 경우, 서버에서 UUID를 생성 후 PK와 FK를 같이 지정해 입력 할 수 있다.

 

 

3. 데이터베이스의 데이터를 합칠 때

흩어져있는 데이터를 합칠때 데이터의 중복이나 충돌 없이 안전하게 데이터를 병합할수 있다.

 

 

 

 

 5. 데이터베이스에 UUID를 도입했을 때 단점

1. 운영 비용의 증가

UUID는 32자리 문자로 이루어져 있으며 몇번을 생성하는 똑같다. BIGINT PK와 비교해보면 더 많은 디스크를 차지하게 되고 인덱스의 크기가 커져 메모리 또한 많이 차지하게 된다.

 

 

2. 정렬이 힘들다

UUID는 랜덤한 값이다 이를 정렬한다는것은 매우 어려워 별도의 인덱스나 생성시간에 따른 정렬을 따로 구현해야 한다.

 

 

3. 몇몇 데이터베이스는 기본 기능으로 제공하지 않는다

현재 가장 많이 사용하고 있는 데이터베이스인 MySQL의 경우, UUID의 자동생성을 기본적으로 제공하지 않는다. MySQL에서 사용할 경우, 함수를 직접 설정해서 UUID를 생성해야 한다.
PostgreSQL은 UUID의 자동생성을 지원하며, UUID를 사용할 경우 PostgreSQL을 사용해 보자

 

 

 

 

 6. import java.util.UUID 메소드 종류

메소드 설명
static UUID randomUUID() 무작위 UUID 생성
static UUID fromString(String uuid) static UUID fromString(String uuid)
long getLeastSignificantBits() UUID의 가장 낮은 64비트 반환
long getMostSignificantBits() UUID의 가장 높은 64비트 반환
int compareTo(UUID val) UUID와 주어진 UUID 비교
String toString() UUID를 문자열로 반환
boolean equals(Object obj) UUID와 주어진 객체가 같은지 여부 반환

 

 

 

 

 

 

 

Lombok에서는 생성자를 생성해주는 기능을 사용할 수 있도록 다음과 같은 어노테이션을 제공해준다.

@NoArgsConstructor 기본 생성자 만드는 데 사용
@AllArgsConstructor 모든 필드의 생성자 만드는 데 사용
@RequiredArgsConstructor 필수 생성자 만드는 데 사용

 

각각의 기본 사용법에 대해 알아볼 예정이다!

 

 

 @NoArgsConstructor

📌 기본 사용법

@NoArgsConstructor
public class BookWithLombok {

    private Long id;
    private String isbn;
    private String name;
    private String author;
}

 

 

📌 자바로 표현했을 때

public class BookWithOutLombok {

    private Long id;
    private String isbn;
    private String name;
    private String author;

    public BookWithOutLombok() {

    }
}

 

 

 

 

 @AllArgsConstructor

클래스에 존재하는 모든 필드에 대한 생성자를 자동으로 생성 

 

📌 기본 사용법

@AllArgsConstructor
public class BookWithLombok {

    private Long id;
    private String isbn;
    private String name;
    private String author;
    private boolean useYn;
}

 

 

📌 자바로 표현했을 때

public class BookWithLombok {
    private Long id;
    private String isbn;
    private String name;
    private String author;
    private boolean useYn;

    public BookWithLombok(final Long id, final String isbn, final String name, final String author, final boolean useYn) {
        this.id = id;
        this.isbn = isbn;
        this.name = name;
        this.author = author;
        this.useYn = useYn;
    }
}

 

 

 

 

 @RequiredConstructor

초기화되지 않은 모든 final 필드, @NonNull로 되어있는 필드들에 대한 생성자를 자동으로 생성한다! 

💡 주의할 점
파라미터의 순서는 클래스에 있는 필드 순서에 맞춰서 생성자 생성
@NonNull 필드들은 null-check가 추가적으로 생성되며, @NonNull이 마크되어 있어도 파라미터에서 null 값이 들어오면 생성자에서 NullPointerException이 발생한다.

 

 

📌 기본 사용법

@RequiredArgsConstructor
public class BookWithLombok {

    private final Long id;
    private final String isbn;
    private final String name;
    private final String author;
    private boolean useYn;
}

 

 

📌 자바로 표현했을 때

public class BookWithLombok {
    private final Long id;
    private final String isbn;
    private final String name;
    private final String author;
    private boolean useYn;

    public BookWithLombok(final Long id, final String isbn, final String name, final String author) {
        this.id = id;
        this.isbn = isbn;
        this.name = name;
        this.author = author;
    }
}

 

 

 

 

 

 

 세부 옵션들

staticName 정적 팩토리 메소드 생성
access 접근제한자 지정
onConstructor 생성자의 어노테이션 지정
force (@NoArgsConstructor만 해당) final 필드가 선언된 경우, 컴파일 타임에 기본값을 0 / null / false 로 설정

 

 

 

staticName

📌 기본 사용법

@NoArgsConstructor(staticName = "of")
public class BookWithLombok {

    private Long id;
    private String isbn;
    private String name;
    private String author;
}

 

 

📌 자바로 표현했을 때

public class BookWithOutLombok { 
    private Long id; 
    private String isbn; 
    private String name; 
    private String author; 

    private BookWithOutLombok() { 
    } 

    public static BookWithOutLombok of() { 
        return new BookWithOutLombok(); 
    } 
}

정적 팩토리 메소드인 of를 생성하고 내부 기본 생성자 생성을 위해 private으로 호출하게 된다! 

 

 

 

access

생성자에 대해 접근제한자 지정 가능! 기본 접근제한자는 public이다. 

접근제한자 목록은 다음과 같다

PUBLIC 모든 곳에서 접근 가능
MODULE 같은 패키지 내에서 접근 가능
PROTECTED 같은 패키지 또는 자식 클래스에서 사용 가능
PACKAGE 같은 패키지 내에서 접근 가능
PRIVATE 내부 클래스에서만 사용 가능
NONE 모든 곳에서 접근 가능

 

 

PUBLIC, NONE

@NoArgsConstructor(access = AccessLevel.PUBLIC)
@NoArgsConstructor(access = AccessLevel.NONE)
public class BookWithLombok {
    private Long id;
    private String isbn;
    private String name;
    private String author;

    public BookWithLombok() {
    }
}

 

 

 

 MODULE, PACKAGE

@NoArgsConstructor(access = AccessLevel.MODULE)
@NoArgsConstructor(access = AccessLevel.PACKAGE)
public class BookWithLombok {
    private Long id;
    private String isbn;
    private String name;
    private String author;

    BookWithLombok() {
    }
}

 

 

 

 PROTECTED

@NoArgsConstructor(access = AccessLevel.PROCTECTED)
public class BookWithLombok {
    private Long id;
    private String isbn;
    private String name;
    private String author;

    protected BookWithLombok() {
    }
}

 

 

 

 PRIVATE

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BookWithLombok {
    private Long id;
    private String isbn;
    private String name;
    private String author;

    private BookWithLombok() {
    }
}

 

 

 

 

 

 

 Java 라이브러리 Lombok, 자주 사용하는 annotation 정리!

Lombok 이란?

어노테이션 기반으로 코드 자동완성 기능을 제공하는 라이브러리.

코드 자동 생성을 통한 편의성, 생산성 증가

코드의 길이가 줄어듬으로 가독성 유지보수성 향상

Builder 패턴의 적용, Log 생성 등 편의성

 

 

 

 

Annotation 정리

@NoArgsConstructor 파라미터(매개변수)가 없는 생성자를 생성한다.
@RequiredArgsConstructor final, @NonNull이 있는 필드를 포함하여 생성자를 생성한다.
@AllArgsConstructor 모든 필드를 파라미터(매개변수)로 갖는 생성자를 생성한다.
@Getter 코드가 compile될 때 getter 메소드 생성한다.
- 속성 @Getter(lazy = true) 사용 시 최초 한 번만 Getter 호출.
이후에는 캐시된 값을 사용한다
@Setter 코드가 compile될 때 setter 메소드 생성한다.
@ToString toString() 메소드 생성한다.
@EqualsAndHashCode equals(), hashCode() 메소드를 생성한다.
@Data @Getter(모든 속성)
@Setter(final이 붙지 않은)
@ToString
@EqualsAndHashCode
@RequiredArgsConstructor
@With with 메소드를 생성한다.
@Builder 해당 클래스에 빌터 패턴을 사용할 수 있도록 해준다
@Log log라는 변수를 이용하여 로그 기능 사용 가능

컴파일 시 : private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(this.class.getName()); 코드가 생성되는 것 
@Log4j, @Slf4J 로그 기능 사용 가능
@SneakyThrows 예외 발생 시 Throwable 타입으로 반환해준다.
JVM(.class)에서 검사 여부 관계 없이 모든 예외에 대해 throw동작.

📌 사용 시 주의해야하는 어노테이션임. 
@Synchronized 메소드에서 동기화 설정
동기화 관련 문제 발생을 해당 어노테이션을 통해 가상의 필드 레벨에서 조금이나마 안전하게 락을 걸어준다 
@NonNull 필드의 값이 null이 될 수 없음을 명시
@Value 불변 클래스(Immutable Class) 를 생성

모든 필드를 Private, Final 로 설정하고 Setter 생성하지 않음.
Final이 붙기 때문에 Setter가 존재할 수 없는 것 !

 

 

 

 

1. 아래 페이지에 접속하여 17 버전을 다운로드

 

Download the Latest Java LTS Free

Subscribe to Java SE and get the most comprehensive Java support available, with 24/7 global access to the experts.

www.oracle.com

 

 

2. 다운 받은 파일 실행

jdk-17_windows-x64_bin.msi 설치파일 더블클릭하여 실행하면 된다 

 

3. Successfully Installed 메시지가 나오면 Java SE 17 설치 성공! 설치 경로 jdk-17 폴더가 나타난다 

 

4. Path 설정

어느 곳에서나 Java를 호출할 수 있도록 Path 설정을 해준다. 위치시킨 JDK 폴더의 경로를 복사해놓은 뒤,

[시작 - 설정 - 시스템 - 정보] 메뉴로 들어가서 [고급 시스템 설정] 을 누른다.

또는 검색에 "고급 시스템 설정 보기" 검색하면 나옴!

 

① 환경 변수 클릭

 

 

② 새로 만들기 클릭

 

 

③ 새 시스템 변수 추가하기

 

 

④ Path 시스템 변수 편집

 

 

⑤ Path 시스템 변수 새로 만들기

[새로 만들기] 버튼 클릭하고 항목이 추가되면 %JAVA_HOME%\bin 입력한다.

등록한 %JAVA_HOME%\bin 을 선택하고 [위로 이동] 버튼을 클릭해서 맨 위로 올려주기! 

 

 

🌟 첫 번째 항목으로 위치시키는 이유

등록된 환경 변수 순서가 중요하기 때문. 명령 라인에서 명령어를 찾을 때, Path 환경 변수에 등록된 순서대로 찾기 때문이다. 

 

 

5. 설정 확인

java -version

cmd에서 위 명령어를 입력하면 설치한 자바 버전 확인 가능!

 

 

 

+ Recent posts

loading