본문 바로가기

Java 길찾기/이것이 자바다

[Java] 기본 API 클래스 - String

어떤 프로그램이건 문자열은 데이터로서 아주 많이 사용된다. 그렇기 때문에 문자열을 생성하는 방법과 추출, 비교, 찾기, 분리, 변환 등을 제공하는 메소드를 잘 익혀두어야 한다.

 

String 생성자

자바의 문자열은 java.lang 패키지의 String 클래스의 인스턴스로 관리된다. 소스상에서 문자열 리터럴은 String 객체로 자동 생성되지만, String 클래스의 다양한 생성자를 이용해서 직접 String 객체를 생성할 수도 있다. String 클래스는 Deprecated(비권장)된 생성자를 제외하고 약 13개의 생성자를 제공한다. Deprecated는 예전 자바 버전에서는 사용되었으나, 현재 버전과 차후 버전에서는 사용하지 말라는 뜻이다. 어떤 생성자를 이용해서 String 객체를 생성할지는 제공되는 매개값의 타입에 따라 달려 있다. 다음은 사용 빈도수가 높은 생성자들이다. 파일의 내용을 읽거나, 네트워크를 통해 받은 데이터는 보통 byte[] 배열이므로 이것을 문자열로 변환하기 위해 사용된다.

// 배열 전체를 String 객체로 생성
String str = new String(byte[] bytes);
// 지정한 문자셋으로 디코딩
String str = new String(byte[] bytes, String charseName);

// 배열의 offset 인덱스 위치부터 length만큼 String 객체로 생성
String str = new String(byte[] bytes, int offset, int length);
// 지정한 문자셋으로 디코딩
String str = new String(byte[] bytes, int offset, int length, String charseName);

 

다음은 바이트 배열을 문자열로 변환하는 예제이다.

// ByteToStringExample.java
public class ByteToStringExample {
    public static void main(String[] args) {
        byte[] bytes = { 72, 101, 108, 108, 111, 32, 74, 97, 118, 97 };
        
        String str1 = new String(byets);
        System.out.println(str1);
        
        String str2 = new String(byets, 6, 4); // 6(74위치), 4(4개)
        System.out.println(str2);
    }
}

 

다음 예제는 키보드로부터 읽은 바이트 배열을 문자열로 변환하는 방법을 보여준다. System.in.read() 메소드는 키보드에서 입력한 내용을 매개값으로 주어진 바이트 배열에 저장하고 읽은 바이트 수를 리턴한다. 예를 들어 Hello를 입력하고 Enter 키를 눌렀다면 Hello + 캐리지리턴(\r) + 라인피드(\n)의 코드값이 바이트 배열에 저장되고 총 7개의 바이트를 읽었기 때문에 7을 리턴한다.

영어는 알파벳 한 자가 1바이트로 표현되지만, 한글과 기타 다른 나라 언어는 2바이트로 표현되기 때문에 입력된 문자 수와 읽은 바이트 수가 다를 수 있다. 바이트 배열을 문자열로 변환하기 위해 다음 예제는 8라인에서 String(byte[] bytes, int offset, int length)를 사용하였는데, length 매개값으로 배열 길이에서 2를 빼준 이유는 캐리지리턴(\r) + 라인피드(\n) 부분은 문자열로 만들 필요가 없기 때문이다. 

// KeyBoardToStringExample.java -- 바이트 배열을 문자열로 변환
public class KeyBoardToStringExample {
    public static void main(String[] args) throws IOException {
        byte[] bytes = new byte[100]; //  읽은 바이트를저장하기 위한 배열 생성
        
        System.out.println("입력: ");
        int readByteNo = System.in.read(bytes); // 배열에 읽은 바이트를 저장하고 읽은 바이트 수를 리턴
        
        String str = new String(bytes, 0 readBytesNo - 2); // 배열을 문자열로 변환
        System.out.println(str);
    }
}

 

String 메소드

String은 문자열의 추출, 비교, 찾기, 분리, 변환 등과 같은 다양한 메소드를 가지고 있다. 그중에서 사용 빈도수가 높은 메소드를 다음과 같이 정리해 보았다.

리턴 타입 메소드명(매개 변수) 설명
char charAt(int index) 특정 위치의 문자 리턴
boolean equals(Object anObject) 두 문자열을 비교
byte[] getBytes() byte[]로 리턴
byte[] getBytes(Charset charset) 주어진 문자셋으로 인코딩한 byte[]로 리턴
int indexOf(String str) 문자열 내에서 주어진 문자열의 위치를 리턴
int length() 총 문자의 수를 리턴
String replace(CharSequence target, CharSequence replacement) target 부분을 replacement로 대치한 새로운 문자열을 리턴
String substring(int beginIndex) beginIndex 위치에서 끝까지 잘라낸 새로운 문자열을 리턴
String substring(int beginIndex, int endIndex) beginIndex 위치에서 endIndex 전까지 잘라낸 새로운 문자열을 리턴
String toLowerCase() 알파벳 소문자로 변환한 새로운 문자열을 리턴
String toUpperCase() 알파벳 대문자로 변환한 새로운 문자열을 리턴
String trim() 앞뒤 공백을 제거한 새로운 문자열을 리턴
String valueOf(int i)
valueOf(double d)
기본 타입값을 문자열로 리턴

String 클래스의 메소드는 모든 프로그램에 자주 사용되기 때문에 코딩을 많이 해본 사람은 메소드의 이름을 거의 다 기억하고 있다. 메소드 이름이 곧 메소드의 기능을 뜻하기 때문에 조금만 코딩해보면 쉽게 기억할 수 있다.

 

String 메소드 - 문자 추출(CharAt())

charAt() 메소드는 매개값으로 주어진 인덱스의 문자를 리턴한다. 여기서 인덱스란 0에서부터 "문자열길이-1" 까지의 번호를 말한다. 다음 코드를 보면서 이해해보자.

String subject = "자바 프로그래밍";
char charValue = subject.charAt(3);

 

"자바 프로그래밍" 문자열은 다음과 같이 인덱스를 매길 수 있다.

더보기

자[0], 바[1], " "[2], 프[3], 로[4], 그[5], 래[6], 밍[7]

charAt(3)은 인덱스3 위치에 있는 문자를 말한다. 즉 '프' 문자가 해당된다. 다음 예제는 주민등록 번호에서 인덱스 7번 문자를 넣어 남자와 여자를 구별한다.

// StringCharAtExample.java -- 남자와 여자를 구별하는 법
public class StringCharAtExample {
    public static void main(String[] args) {
        String ssn = "123456-1230123"
        char gender = ssn.charAt(7);
        switch(gender) {
            case '1':
            case '3':
                System.out.println("남자 입니다.");
                break;
            case '2':
            case '4':
                System.out.println("여자입니다.");
                break;
        }
    }
}

 

String 메소드 - 문자열 비교(equals())

기본 타입 변수의 값을 비교할 때에는 == 연산자를 사용한다. 그러나 문자열을 비교할 때에는 == 연산자를 사용하면 원하지 않는 결과가 나올 수 있다. 다음 코드를 보면서 이해해보자.

String strVar1 = new String("홍길동");
String strVar2 = "홍길동";
String strVar3 = "홍길동";

 

자바는 문자열 리터럴이 동일하다면 동일한 String 객체를 참조하도록 되어 있다. 그래서 strVar2와 strVar3는 동일한 String 객체를 참조한다. 그러나 strVar1은 new 연산자로 생성된 다른 String 객체를 참조한다.

이 경우 변수 strVar1과 strVar2의 == 연산은 false를 산출하고 strVar2와 strVar3의 == 연산은 true를 산출한다. == 연산자는 각 변수에 지정된 번지를 비교하기 때문에 이러한 결과가 나온다.

strVar1 == strVar2 // false
strVar2 == strVar3 // true

만약 두 String 객체의 문자열만을 비교하고 싶다면 == 연산자 대신에 equals() 메소드를 사용해야 한다.

strVar1.equals(strVar2) // true
strVar2.equals(strVar3) // true

 

원래 equals()는 Object의 번지 비교 메소드이지만, String 클래스가 오버라이딩해서 문자열을 비교하도록 변경했다.

// StringEqualsExample.java -- 문자열 비교
public class STringEqualsExample {
    public static void main(String[] args) {
        String strVar1 = new String("홍길동");
        String strVar2 = "홍길동";
        
        if(strVar1 == strVar2) {
            System.out.println("같은 String 객체를 참조.");
        }
        else {
            System.out.println("다른 Strnig 객체를 참조.");
        }
        
        if(strVar1.equals(strVar2)) {
            System.out.println("같은 문자열을 가짐");
        }
        else {
            System.out.println("다른 문자열을 가짐");
        }
    }
}

 

String 메소드 - 바이트 배열로 변환(getBytes())

종종 문자열을 바이트 배열로 변환하는 경우가 있다. 대표적인 예로 네트워크로 문자열을 전송하거나, 문자열을 암호화할 때 문자열을 바이트 배열로 변환한다. 문자열을 바이트 배열로 변환하는 메소드는 다음 두 가지가 있다.

byte[] bytes = "문자열".getBytes();
byte[] bytes = "문자열".getBytes(Charset charset);

 

getBytes() 메소드는 시스템의 기본 문자셋으로 인코딩된 바이트 배열을 리턴한다. 만약 특정 문자셋으로 인코딩된 바이트 배열을 얻으려면 두 번째 메소드를 사용하면 된다. 다음은 EUC-KR과 UTF-8로 각각 인코딩된 바이트 배열을 리턴한다.

try {
    byte[] bytes = "문자열".getBytes("EUC-KR");
    byte[] bytes = "문자열".getBytes("UTF-8");
} 
catch (UnsupportedEncodingException e) {
}

어떤 문자셋으로 인코딩하느냐에 따라 바이트 배열의 크기가 달라지는데, EUC-KR은 getBytes()와 마찬가지로 알파벳은 1파이트, 한글은 2바이트로 변환하고, UTF-8은 알파벳은 1파이트, 한글은 3바이트로 변환한다. getBytes(Charset charset) 메소드는 잘못된 문자셋을 매개값으로 줄 경우, java.io.UnsupportedEncodingException 예외가 발생하므로 예외 처리가 필요하다.

 

바이트 배열을 다시 문자열로 변환(디코딩) 할 때에는 어떤 문자셋으로 인코딩된 바이트 배열이냐에 따라서 디코딩 방법이 다르다. 단순하게 String(byte[] bytes) 생성자를 이용해서 디코딩하면 시스템의 기본 문자셋을 이용한다. 시그템 기본 문자셋과 다른 문자셋으로 인코딩된 바이트 배열일 경우 다음 String 생성자를 이용해서 디코딩해야 한다.

String str = new String(byte[] bytes, String charseName);

 

다음 예제에서는 문장열을 배열로 인코딩하고 길이를 출력해 보았다. 그리고 다시 String 생성자를 이용해서 문자열로 디코딩해 보았다.

// StringGetBytesExample.java -- 바이트 배열로 변환
public class StringGetBytesExample {
    public static void main(String[] args) {
        String str = "안녕하세요";
        
        byte[] byte1 = str.getBytes();
        System.out.println("bytes1.length: " + bytes1.length);
        String str1 = new String(bytes1);
        System.out.println("bytes1 -> String: " + str1);
        
        try {
            byte[] byte2 = str.getBytes("EUC-KR");
            System.out.println("bytes2.length: " + bytes2.length);
            String str2 = new String(bytes2, "EUC-KR");
            System.out.println("bytes2 -> String: " + str2);
        
            byte[] byte3 = str.getBytes("URF-8");
            System.out.println("bytes3.length: " + bytes3.length);
            String str3 = new String(bytes3, "URF-8");
            System.out.println("bytes3 -> String: " + str3);
        }
        catch(UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}

 

String 메소드 - 문자열 찾기(indexOf())

indexOf() 메소드는 매개값으로 주어진 문자열이 시작되는 인덱스를 리턴한다. 만약 주어진 문자열이 포함되어 있지 않으면 -1을 리턴한다. 다음 코드를 보면서 이해해보자.

String subject = "자바 프로그래밍";
int index = subject.indexOf("프로그래밍");

index 변수에는 3이 저장되는데, "자바 프로그래밍"에서 "프로그래밍"문자열의 인덱스의 시작 위치가 3이기 때문이다.

 

indexOf() 메소드는 if문의 조건식에서 특정 문자열이 포함되어 있는지 여부에 따라 실행 코드를 달리할 때 자주 사용된다. -1값을 리턴하면 특정 문자열이 포함되어 있지 않다는 뜻이다.

if( 문자열.indexOf("찾는문자열") != -1 ) {
    // 포함되어 있는 경우
}
else {
    // 포함되어 있지 않은 경우
}
// StringIndexOfExample.java -- 문자열 포함 여부 조사
public class StringIndexOfExample {
    public static void main(String[] args) {
        String subject = "자바 프로그래밍";
        
        int location = sub.indexOf("프로그래밍");
        System.out.println(location);
        
        if(subject.indexOf("자바") != -1) {
            System.out.println("자바와 관련된 책입니다.");
        }
        else {
            System.out.println("자바와 관련되지 않은 책입니다.");
        }
    }
}

 

String 메소드 - 문자열 길이(length())

length() 메소드는 문자열의 길이(문자의 수)를 리턴한다. 다음 코드를 보면서 이해해보자.

String subject = "자바 프로그래밍";
int length = subject.length();

length 변수에는 8이 저장된다. subject 객체의 문자열 길이는 공백을 포함해서 8개이기 때문이다.

 

// StringLengthExample.java -- 문자열의 문자 수 얻기
public class StringLengthExample {
    public static void main(String[] args) {
        String ssn = "1234561230123";
        
        int length = ssn.length();
        if(length == 13) {
            System.out.println("주민번호 자리수가 맞습니다.");
        }
        else {
            System.out.println("주민번호 자리수가 틀립니다.");
        }
    }
}

 

String 메소드 - 문자열 대치(replace())

replace() 메소드는 첫 번째 매개값인 문자열을 찾아 두 번째 매개값인 문자열로 대치한 새로운 문자열을 생성하고 리턴한다. 다음 코드를 보면서 이해해보자.

String oldStr = "자바 프로그래밍";
String newStr = oldStr.replace("자바", "JAVA");

String 객체의 문자열은 변경이 불가한 특성을 갖기 때문에 replace() 메소드가 리턴하는 문자열은 원래 문자열의 수정본이 아니라 완전히 새로운 문자열이다. 따라서 newStr 변수는 다음 그림과 같이 새로 생성된 "JAVA 프로그래밍" 문자열을 참조한다.

 

// StringReplaceExample.java -- 문자열 대치하기
public class StringReplaceExample {
    public static void main(String[] args) {
        String oldStr = "자바는 객체지향언어 입니다. 자바는 많은 API를 지원합니다.";
        String newStr = oldStr.replace("자바", "JAVA");
        System.out.println(oldStr);
        System.out.println(newStr);
    }
}

 

String 메소드 - 문자열 잘라내기(substring)

substring() 메소드는 주어진 인덱스에서 문자열을 추출한다. substring() 메소드는 매개값의 수에 따라 두 가지 형태로 사용된다. substring(int beginIndex, int endIndex)는 주어진 시작과 끝 인덱스 사이의 문자열을 추출하고, substring(int beginIndex)는 주어진 인덱스부터 끝까지 문자열을 추출한다.

String ssn = "123456-1234567";
String firstNum = ssn.substring(0, 6);
String secondNum = ssn.substring(7);

위 코드에서 firstNum 변수값은 "123456" 이고, secondNum 변수값은 "1234567"이다. ssn.substring(0, 6)은 인덱스 0(포함)~6(제외) 사이의 문자열을 추출하는 것이고, substring(7)은 인덱스 7부터의 문자열을 추출한다.

 

// StringSubstringExample.java -- 문자열 추출하기
public class StringSubstringExample {
    public static void main(String[] args) {
        String ssn = "123456-1234567";
        
        String firstNum = ssn.substring(0, 6);
        System.out.println(firstNum);
        
        String secondNum = ssn.substring(7);
        System.out.println(secondNum);
    }
}

 

String 메소드 - 알파벳 소문자, 대문자 변경(toLowerCase(), toUpperCase())

toLowerCase() 메소드는 문자열을 모두 소문자로 바꾼 새로운 문자열을 생성한 후 리턴한다. 반대로 toUpperCase() 메소드는 문자열을 모두 대문자로 바꾼 새로운 문자열을 생성한 후 리턴한다. 다음 코드를 보면서 이해해보자.

String original = "Java Programming";
String lowerCase = original.toLowerCase();
String upperCase = original.toUpperCase();

lowerCase 변수는 새로 생성된 "java programming" 문자열을 참조하고 upperCase 변수는 새로 생성된 "JAVA PROGRAMMING" 문자열을 참조한다. 원래 "Java Programming" 문자열이 변경된 것은 아니다.

 

toLowerCase()와 toUpperCase() 메소드는 영어로 된 두 문자열을 대소문자와 관계없이 비교할 때 주로 이용된다. 다음 에제에서는 두 문자열이 대소문자가 다를 경우 어떻게 비교하는지를 보여준다. equals() 메소드를 사용하려면 사전에 toLowerCase()와 toUpperCase()로 대소문자를 맞추어야 하지만, equalsIgnoreCase() 메소드를 사용하면 이 작업이 생략된다.

// StringToLowerUpperCaseExample.java -- 전부 소문자 또는 대문자로 변환
public class StringToLowerUpperCaseExample {
    public static void main(String[] args) {
        String str1 = "Java Programming";
        String str2 = "JAVA Programming";
        
        System.out.println(str1.equals(str2));
        
        String lowerStr1 = str1.toLowerCase();
        String lowerStr2 = str2.toLowerCase();
        System.out.println(lowerStr1.equals(lowerStr2));
        
        System.out.println(str1.equalsIgnoreCase(str2));
    }
}

 

Strnig 메소드 - 문자열 앞뒤 공백 잘라내기(trim())

trim() 메소드는 문자열의 앞뒤 공백을 제거한 새로운 문자열을 생성하고 리턴한다. 다음 코드를 보면 newStr 변수는 새로 생성된 "자바 프로그래밍" 문자열을 참조한다. trim() 메소드는 앞뒤의 공백만 제거할 뿐 중간의 공백은 제거하지 않는다.

String oldStr = "    자바 프로그래밍    ";
String newStr = oldStr.trim();

trim() 메소드를 사용한다고 해서 원래 문자열의 공백이 제거되는 것은 아니다. 

 

// StringTrimExample.java -- 앞뒤 공백 제거
public class StringTrimExample {
    public static void main(String[] args) {
        String tel1 = "   02";
        String tel2 = "1234    ";
        String tel3 = "  5678  ";
        
        String tel = tel1.trim() + tel2.trim() + tel3.trim();
        System.out.println(tel);
    }
}

 

String 메소드 - 문자열 변환(valueOf())

valueOf() 메소드는 기본 타입의 값을 문자열로 변환하는 기능을 가지고 있다. String 클래스에는 매개 변수의 타입별로  valueOf() 메소드가 다음과 같이 오버로딩되어 있다.

static String valueOf(boolean b)
static String valueOf(char c)
static String valueOf(int i)
static String valueOf(long l)
static String valueOf(double d)
static String valueOf(float f)
// StringValueOfExample.java -- 기본 타입 값을 문자열로 변환
public class StringValueOfExample {
    publid static void main(String[] args) {
        String str1 = String.valueOf(10);
        String str2 = String.valueOf(10.5);
        String str3 = String.valueOf(true);
        
        System.out.println(str1);
        System.out.println(str2);
        System.out.println(str3);
    }
}