본문 바로가기
java

[Java] 표준 API #3 - String / StringBuffer, Builder / StringTokenizer, Pattern

by jinbro 2017. 10. 9.

[API 설명]

1) java.lang.String

- char[] 래핑

- immutable Object : 힙영역에 1 생성되면 값을 변경할 없음

=> 영역에서 변경이 불가하다는 : 최적화(같은 문자열 == 같은 객체 - 공유), 안전성

=> 새로운 객체를 생성해서 참조 객체주소값을 변경하는

=> 보통 final 클래스로 선언 : 상속해서 Immutable 속성을 없애버릴 수도 있음


- Charset 신경쓰기 : UTF-8, EUC-KR 따라 한글 인코딩 길이가 다름

import java.io.UnsupportedEncodingException;

public class StringTest {
public static void main(String[] args) {

/* byte[]을 String으로 : 네트워크 통신 데이터 byte[](String의 생성자는 여러개) */
byte[] data = {72, 101, 108, 108, 111};
String msg = new String(data);//byte -> char unicode
System.out.println(msg);
/**** 주의할점 : 알파벳은 1바이트, 한글을 포함한 영어 이외 언어는 2바이트 ****/


//charAt(idx) : 문자열 중 특정 index 문자를 리턴함, String은 char[]를 래핑
System.out.println(msg.charAt(0));


/* equals
1) 문자열의 equals는 객체가 가진 데이터값(문자열 요소)을 비교함 : String에서 equals를 오버라이딩
2) 문자열 값을 비교할 때 ==을 쓰면 참조 객체 주소 비교가 되어버려서 원치않은 결과가 리턴됨
*/
String msg2 = new String("Hello");
System.out.println(msg.equals(msg2)); // true


/* getBytes
1) byte[]로 리턴
2) 네트워크 전송용, 문자열 암호화
*/
String msg3 = "안녕하세요";
byte[] data3 = null;
byte[] data4 = null;

try {
//한글 인코딩 Charset에 따라서 길이가 다름
data3 = msg3.getBytes("UTF-8");
data4 = msg3.getBytes("EUC-KR");
//EUC-KR, 배열 초기화 크기를 유동적으로, 지정해주지않으면 시스템 기본 Charset을 사용함
/*
[데이터가 왔다리 갔다리할 때 Charset을 신경써야한다]
EUC-KR : 한글 2바이트, UTF-8 : 한글 3바이트 - 어떤 차이일지 찾아보기
- 공간 상으로는 EUC-KR이 좋은 것 같은데 다시 UTF-8 가고 있다던데
- https://groups.google.com/forum/#!topic/clojure-kr/R1cRgy9Zugk

1) Unicode : 세상 모든 문자를 나타내는 코드, 2바이트로 표현 - /u0000 ~ /uffff
1-2) utf-8 : 1~4바이트 가변길이 인코딩 방식(기존 아스키코드를 사용하던, 1바이트로 알파벳을 나타낼 수 있었던 영어권 나라...)
- 웹표준을 관리하는 W3C에서 권장
- 한글은 3바이트
- 자바 String 객체 : UTF-16

2) EUC-KR : 한국에서 한글을 표현하기위해서 사용한 인코딩 방식

*/
System.out.println("UTF-8 leng : " + data3.length + ", EUC-KR leng : " + data4.length);
}catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
for(int i=0; i<data3.length; i++){
System.out.println(data3[i]);
}


/*
indexOf
1) 주어진 문자열(파라미터)의 위치(인덱스)를 리턴
2) 없으면 -1
3) 파라미터 문자열이 모두 일치해야 0을 리턴
*/
int idx = msg.indexOf("lo");
if(idx < 0){
System.out.println("없어요");
} else {
System.out.println("찾았어요");
}


//length : 문자열 길이 리턴(공백도 문자열이다 : \u0009
System.out.println(msg.length());


/*
replace
1) target 부분을 replacement로 대치한 새로운 문자열 리턴, Pattern, Matcher 클래스(java.util.regex)사용
2) 파라미터 타입은 CharSequence : String이 구현했음, CharSequence 인터페이스 메서드 목록보기
*/
String newMsg = msg.replace("H", "h");
System.out.println(msg + ", " + newMsg);


// substring : 원하는 위치까지, 원하는 위치부터 잘라낸 문자열을 리턴함(인덱스 잘못지정하면 익셉션 발생)
try{
String splitMsg = msg.substring(10);
} catch(StringIndexOutOfBoundsException e){
/* String 전용 익셉션 : IndexOutOfBoundsException 상속 */
System.out.println(e.getMessage());
}


/*
toLowerCase, toUpperCase
1) 문자열을 소문자 혹은 대문자로 변경해서 새로운 문자열로
2)
*/
String upperMsg= msg.toUpperCase();
String lowerMsg = msg.toLowerCase();
System.out.println("원래 : " + msg + ", 대문자 : " + upperMsg + ", 소문자 : " + lowerMsg);


//trim : 앞 뒤 공백문자 없애줌
String trimMsg = " 안녕하세요 ".trim();
System.out.println(trimMsg);


//valueOf : primitive val -> String, static method
int num = 10;
String trans = String.valueOf(num);
System.out.println(trans);


//split : 문자열을 정규표현식 기준으로 쪼갬, 새로운 String 배열 리턴
String target = "가&나,다,라,마-바";
String[] result = target.split("&|,|-");

for(String word : result){
System.out.println(word);
}
}
}


2) java.util.StringTokenizer

- String 유틸리티

- 정규표현식이 아닌 특정 delimiter 기준으로 문자열을 분할 유틸리티

import java.util.StringTokenizer;

public class StringTokenizerTest {

public static void main(String[] args) {

String target = "가, 나, 다, 라, 마, 바";
StringTokenizer st = new StringTokenizer(target, ", ", false);

/* countTokens, hasMoreTokens
1) 델리미터에 의해 끊어진 문자열을 얻어올 떄 체크
2) 무작정 꺼내오기부터한다면(nextToken) NoSuchElementException 발생 위험
*/
int cnt = st.countTokens();
System.out.println(cnt);

while(st.hasMoreTokens()){
System.out.println(st.nextToken());
}
}
}



3) java.lang.StringBuffer, java.lang.StringBuilder

- String

(1) immutable Object : 같은 문자열이면서 각각 객체가 생성된다면 메모리 손실(그래서 immutable 이라는데 설계 이유 찾아보기)

(2) 변경 작업이 많다면 String 인스턴스를 그만큼 생성함 : 메모리 손실


- StringBuffer

(1) String처럼 문자열 일부 변경 요청에 변경한 결과를 새로운 문자열을 만들어 리턴하지않음

(2) 내부 버퍼(내부 코드를 보면 char[capacity] 인스턴스 생성할 크기 지정가능) 문자열을 저장해두고 내부에서 변경작업을

- Buffer Builder 자동적으로 버퍼사이즈를 늘림 : 같은 AbstractStringBuilder 상속받고있음


(3) 버퍼란

- 개체 사이의 완충재 역할 : 완충기억장치

- 임시 저장 공간 : 사이즈가 한정되어있음

- FIFO 구조() : 먼저 들어온 데이터가 먼저 나감


(4) StringBuffer 메서드는 synchronized 처리 - 동기화 처리, 멀티쓰레드에 안전(쓰레드 공부하면서 이해해보도록 합시다)

public class StringBufferTest {
public static void main(String[] args) {

/*
StringBuffer
1) 기본적으로 16 길이 지정 : 버퍼 사이즈 설정
2) sb.append 등 변경 작업 결과 : this 리턴(메서드 체이닝 : 자기 자신 리턴 - 호출 - 리턴 - 호출 반복)
*/
StringBuffer sb = new StringBuffer().append(1);

String result = sb.toString();
System.out.println(result);

}
}



- StringBuilder

(1) StringBuffer 사용방식, 내부구조는 같음

(2) 멀티쓰레드에 안전한지 그렇지 않은지 차이 : 멀티쓰레드 환경이라면 StringBuffer, 싱글쓰레드 환경이라면 StringBuilder

public class StringBuilderTest {

public static void main(String[] args) {
StringBuilder sb = new StringBuilder(30);
sb.append('c');
sb.append('h');
sb.append('a');
sb.append('r');

sb.insert(0, 'x');
sb.deleteCharAt(sb.length()-1);

String result = sb.toString();
System.out.println(result);
}
}



4) java.util.regex.Pattern

- 정규표현식과 관련한 처리를 있는 유틸리티 클래스

import java.util.regex.Pattern;

public class PatternTest {
public static void main(String[] args) {
/*
[간단한 정규표현식]
1) [ ] : 1개의 문자, [abc] : a b c 중 1개 / [a-zA-Z] a~z, A~Z 중 1개
2) /d : 1개의 숫자, [0-9]와 동일
3) \s : 공백
4) \w : 1개의 알파벳 또는 1개의 숫자, [a-zA-Z_0-9]와 동일
5) ? : 없음 또는 1개
6) * : 없는 또는 1개 이상
7) + : 1개 이상
8) {n} : n개
9) {n,} : 최소 n개 이상
10) {n,m} : n개에서 m개까지
11) () : 그룹핑
12) \. : .
13) . : 모든 문자 중에서 1개의 문자

폰번호 : 010-\d{4}-\d{4}
이메일 : [a-z_0-9]+@[a-z_0-9]+\.[a-z_0-9]
*/

// matches : 정규표현식과 값을 비교했을 때 정규표현식에 맞는 표현인지 체크해줌, static 메서드
String emailRegex = "[a-z_0-9]+@[a-z_0-9]+\\.[a-z_0-9]+" ;
System.out.println(Pattern.matches(emailRegex, "jinbro@likelion.org"));
}
}




댓글