11일차(2) - 기본API

은채의 성장통·2025년 6월 12일

KCC정보통신

목록 보기
16/30

기본 API 클래스

1. 문자열 클래스

문자열 처리 클래스 비교 (String, StringBuffer, StringBuilder)

자바에서는 문자열을 다룰 때 String, StringBuffer, StringBuilder 세 가지 클래스를 사용할 수 있다.

각 클래스는 메모리 관리 방식과 동기화 처리 방식이 다르기 때문에 적절하게 선택해야 한다.

클래스특징수정 가능 여부멀티 스레드 안전성성능
String불변(Immutable) 객체❌ (변경 불가, 새로운 객체 생성)✅ (자동으로 동기화됨)낮음 (많이 변경되면 성능 저하)
StringBuffer가변(Mutable) 객체✅ (내용 변경 가능)✅ (멀티 스레드 안전)보통 (멀티 스레드 환경에서 안정적)
StringBuilder가변(Mutable) 객체✅ (내용 변경 가능)❌ (동기화 X, 단일 스레드 전용)높음 (빠른 문자열 처리)

1.1 문자열 클래스와 성능

문자열 변경 시 String의 문제점

String str = "abc";
str = str.concat("123"); // 새로운 객체가 생성됨

위 코드는 "abc123"이라는 새로운 객체를 생성하는 방식이다. 기존 "abc" 객체는 변경되지 않고 새로운 객체가 메모리에 생성되므로 성능이 저하될 수 있다.

문자열을 자주 변경할 경우 StringBufferStringBuilder 사용

StringBuffer sb = new StringBuffer("abc");
sb.append("123"); // 기존 객체 자체를 변경

위 코드는 객체를 새로 생성하지 않고 기존 객체 자체를 변경하기 때문에 메모리 효율이 높고 성능이 향상됨.


1.2 문자열 자르기

자바에서 문자열을 분리하는 방법에는 StringTokenizersplit() 메서드가 있다.

메서드반환 타입설명
split(String regex)String[]지정된 정규 표현식을 기준으로 문자열을 분리하여 배열 반환
split(String regex, int limit)String[]limit 개수만큼 문자열을 분리하여 배열 반환
StringTokenizerStringTokenizer구분자를 이용해 문자열을 하나씩 가져오는 방식

문자열 분리 예제 (StringTokenizer vs split())

import java.util.StringTokenizer;

public class StringSplitExample {
    public static void main(String[] args) {
        String accessLog = "2017,03,11,,,USER123,GROUP1";

        // 1. StringTokenizer 사용
        System.out.println("***** StringTokenizer *****");
        StringTokenizer accessTokens = new StringTokenizer(accessLog, ",");
        System.out.println("토큰 개수: " + accessTokens.countTokens());
        while (accessTokens.hasMoreTokens()) {
            System.out.println(accessTokens.nextToken());
        }

        // 2. split() 사용
        System.out.println("\n***** split() *****");
        String[] splits = accessLog.split(",");
        System.out.println("배열 개수: " + splits.length);
        for (String str : splits) {
            System.out.println(str);
        }

        // 3. split()에서 개수 제한
        System.out.println("\n***** split() (limit = 3) *****");
        String[] splits2 = accessLog.split(",", 3);
        System.out.println("배열 개수: " + splits2.length);
        for (String str : splits2) {
            System.out.println(str);
        }
    }
}

1.3 StringTokenizer vs split() 비교

구분StringTokenizersplit()
분리 방식특정 구분자를 기준으로 하나씩 가져옴정규 표현식 사용 가능
반환 타입StringTokenizer 객체String[] (배열 반환)
공백 포함 여부연속된 구분자를 무시빈 문자열도 배열 요소로 포함
정규 표현식 지원❌ (단순 구분자만 사용 가능)✅ (복잡한 패턴 매칭 가능)

정리

  • 문자열을 자주 변경할 경우 String 대신 StringBuffer 또는 StringBuilder를 사용해야 성능이 향상됨.
  • StringTokenizer는 단순한 구분자로 문자열을 나눌 때 유용하지만, 정규 표현식을 활용하려면 split()을 사용하는 것이 더 효율적임.
  • split()은 빈 문자열도 배열 요소로 포함하지만, StringTokenizer는 연속된 구분자를 자동으로 무시함.

2. 정규 표현식

정규 표현식이란?

정규 표현식(Regular Expressions, regex)은 특정 패턴을 가진 문자열을 찾거나 수정할 때 사용하는 표준화된 텍스트 패턴이다.

이를 활용하면 문자열 검색, 유효성 검사, 데이터 변환 등 다양한 작업을 수행할 수 있다.


횟수 지정 메타 문자

횟수를 지정하는 메타 문자는 특정 패턴이 몇 번 반복되는지를 정의할 때 사용된다.

메타 문자설명예시
*0회 이상 반복a*"a", "aa", ""
+1회 이상 반복a+"a", "aa" (공백 불가)
?0회 또는 1회a?"a" 또는 ""
{n}정확히 n회 반복a{3}"aaa"
{n,}최소 n회 반복a{2,}"aa", "aaa", "aaaa"
{n,m}n~m회 반복a{2,4}"aa", "aaa", "aaaa"

가장 많이 쓰이는 정규 표현식 메타 문자

메타 문자설명예시
.임의의 단일 문자a.b"acb", "a0b"
\d숫자 (0~9)\d+"123", "98765"
\w영문자, 숫자, _\w+"abc", "A1_B"
\s공백 문자"hello\sworld""hello world"
\b단어의 경계\bcat\b"cat"(단독)
^문자열의 시작^abc"abc"로 시작하는 문자열
$문자열의 끝xyz$"xyz"로 끝나는 문자열
``OR 연산
[]문자셋 지정[abc]"a", "b", "c"
()그룹 지정(abc)+"abc", "abcabc"

2.1 정규 표현식 (Pattern과 Matcher)

Java의 PatternMatcher 클래스를 사용하여 정규 표현식을 활용할 수 있습니다. 가장 많이 쓰이는 메서드 중 하나가 find()로, 주어진 문자열에서 패턴과 일치하는 부분을 찾을 때 사용됩니다.

예제 코드: 전화번호 찾기

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexMatcherExample {
    public static void main(String[] args) {
        // 검색할 문자열 (고객 정보)
        String customerInfo =
            "홍길동은 30세이며 서울시 강남구에 거주합니다. " +
            "그의 집 전화번호는 02-234-5678이며 " +
            "휴대폰 번호는 011-234-5678입니다.";

        // 정규 표현식: 전화번호 형식 (xx-xxx-xxxx 또는 xxx-xxxx-xxxx)
        String pattern = "\\d{2,3}-\\d{3,4}-\\d{4}";

        // 정규 표현식 패턴을 컴파일
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(customerInfo);

        int count = 0;

        // find()를 이용하여 패턴과 일치하는 부분 찾기
        while (m.find()) {
            count++;
            System.out.print("찾은 위치 : " + m.start() + "\t"); // 시작 위치 출력
            System.out.println("전화번호 : " + m.group());       // 찾은 전화번호 출력
        }

        System.out.println("발견된 전화번호 수 : " + count);
    }
}

설명

  • Pattern.compile(pattern): 정규 표현식을 컴파일하여 Pattern 객체 생성
  • p.matcher(customerInfo): customerInfo 문자열에서 패턴을 찾을 Matcher 객체 생성
  • m.find(): 일치하는 패턴이 있으면 true 반환하며, 여러 개 존재할 경우 반복 실행
  • m.start(): 일치하는 패턴의 시작 위치 반환
  • m.group(): 찾은 패턴(전화번호)을 반환

추가 개념

  • 정규 표현식의 활용: 이메일, 주민번호, IP 주소 검출 등 다양한 데이터 패턴 매칭에 사용 가능
  • 다른 메서드
    • m.matches(): 문자열 전체가 패턴과 일치하는지 확인
    • m.replaceAll("변경할 문자열"): 패턴과 일치하는 모든 문자열을 변경

3. Object 클래스

Java의 Object 클래스는 모든 클래스의 최상위 부모 클래스이며, 모든 객체는 Object를 직접 또는 간접적으로 상속받습니다.

  • 객체 동등 비교

객체를 비교하는 방법에는 == 연산자와 equals() 메서드가 있습니다.

public class ObjectComparisonExample {
    public static void main(String[] args) {
        String str1 = new String("Hello");
        String str2 = new String("Hello");

        // == 연산자는 객체의 주소값을 비교
        System.out.println("주소 비교 (==) : " + (str1 == str2)); // false

        // equals() 메서드는 객체의 내용 비교
        System.out.println("내용 비교 (equals) : " + str1.equals(str2)); // true
    }
}

설명

  • == 연산자: 두 객체가 같은 메모리 주소를 가리키는지 비교 → 즉, 동일한 객체인지 확인 (false)
  • equals(): 객체가 같은 내용을 가지고 있는지 비교 → 대부분의 클래스에서는 equals()를 재정의하여 비교 (true)

3.1 hashCode()와 equals()

모든 객체는 hashCode()equals() 메서드를 가지고 있으며, 두 메서드는 서로 연관이 있습니다.

import java.util.Objects;

class Person {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // equals() 메서드 오버라이드
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof Person)) return false;
        Person person = (Person) obj;
        return age == person.age && Objects.equals(name, person.name);
    }

    // hashCode() 메서드 오버라이드
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

public class HashCodeEqualsExample {
    public static void main(String[] args) {
        Person p1 = new Person("Alice", 25);
        Person p2 = new Person("Alice", 25);
        Person p3 = new Person("Bob", 30);

        System.out.println("p1과 p2 비교 (equals): " + p1.equals(p2)); // true
        System.out.println("p1과 p3 비교 (equals): " + p1.equals(p3)); // false
        System.out.println("p1의 해시코드: " + p1.hashCode());
        System.out.println("p2의 해시코드: " + p2.hashCode());
        System.out.println("p3의 해시코드: " + p3.hashCode());
    }
}

설명

  • equals() 메서드를 재정의하면 객체의 내용을 비교 가능 (nameage가 동일하면 true)
  • hashCode()는 객체의 해시값을 반환하며, 같은 내용일 경우 동일한 해시코드가 생성됨
  • HashMap, HashSet 등의 자료구조에서 중복 객체를 처리할 때 hashCode()가 필수적으로 사용됨

추가적인 개념

  1. 객체의 toString() 오버라이드

    • Object 클래스의 toString()을 재정의하면 객체의 정보를 쉽게 출력 가능
    class Employee {
        String name;
        int age;
    
        public Employee(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Employee{name='" + name + "', age=" + age + "}";
        }
    }
    
    public class ToStringExample {
        public static void main(String[] args) {
            Employee emp = new Employee("John", 30);
            System.out.println(emp.toString()); // Employee{name='John', age=30}
        }
    }
    
  2. 객체 비교 시 주의할 점

    • equals()를 오버라이드하면 반드시 hashCode()도 오버라이드할 것 (HashSet 사용 시 필수)
    • 기본형 변수 비교는 == 사용, 참조형 객체 비교는 equals() 사용 추천

요약

  • PatternMatcher 클래스를 사용해 정규 표현식 패턴을 매칭 가능 (find() 활용)
  • Object 클래스는 모든 클래스의 부모이며 equals(), hashCode(), toString() 등을 오버라이드 가능
  • == 연산자는 객체의 주소를 비교, equals()는 객체의 내용을 비교
  • hashCode()를 올바르게 구현하면 해시 기반 자료구조에서 객체 관리 가능

3.2 Record 클래스와 Lombok 라이브러리 정리

  • 1. Record 클래스
  • Java 14에 추가된 새로운 클래스 유형으로, 값을 가지는 클래스를 간편하게 정의 가능.
  • record 선언 시 컴파일러가 private 멤버 변수, 생성자, hashCode(), equals(), toString() 및 필드 이름과 동일한 getter 메서드를 자동으로 추가.
  • 제약 사항
    • setter 메서드가 없음 → 객체의 값을 변경할 수 없음.
    • 필드 이름과 동일한 getter 메서드 사용 → 기존의 getter (getEmpId() 등) 방식과 혼동될 가능성이 있음.
    • DTO(Data Transfer Object)나 VO(Value Object) 생성 시 값 변경이 필요할 경우 적합하지 않음.
  • 2. Lombok 라이브러리
  • Java 표준 라이브러리는 아니지만 DTO/VO 클래스 작성 시 자주 사용.
  • 어노테이션을 통해 생성자, setter/getter, hashCode()/equals(), toString() 등을 자동 생성.
  • 설치 방법
    1. Lombok 다운로드
    2. lombok.jar 파일을 Eclipse 디렉토리에 복사
    3. eclipse.ini 파일 맨 아래에 javaagent:lombok.jar 추가
    4. 프로젝트의 Build Path -> Configure Build Path -> Libraries 탭에서 lombok.jar 추가
  • 3. Lombok 주요 어노테이션
어노테이션설명
@Datagetter, setter, hashCode(), equals(), toString() 자동 추가
@Gettergetter 메서드 추가
@Settersetter 메서드 추가 (final 필드 제외)
@EqualsAndHashCodehashCode()equals() 추가
@ToStringtoString() 메서드 추가
@NoArgsConstructor기본 생성자 추가 (final 필드가 있으면 force=true 필요)
@AllArgsConstructor모든 필드를 초기화하는 생성자 추가
@RequiredArgsConstructorfinal 필드 및 @NonNull 필드 초기화하는 생성자 추가
  • 4. Lombok 적용 코드 예시
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

@Data
@RequiredArgsConstructor
@NoArgsConstructor(force=true)
public class Employee {
    private final int employeeId;
    @NonNull private String name;
    @NonNull private String email;
    private String phoneNumber;
    @NonNull private String jobId;
}
profile
인생 별거 없어

0개의 댓글