15. String
String
- String 클래스는 final로 선언되어 있기에 다른 클래스에게 상속하지 못한다.
= 다른 클래스들이 확장하지 못한다. - Serializable, Comparable<String>, CharSequence 인터페이스를 구현하는 클래스다.
- Serializable : 구현해야하는 메소드가 하나도 없는 특이한 인터페이스로 Serializable 인터페이스를 구현한다고 선언하면 해당 객체를 파일로 저장하거나 다른 서버에 전송 가능한 상태가 된다.
- Comparble : compareTo() 메소드 하나만 선언되어 있다. 이 메소드는 매개 변수로 넘어가는 객체와 현재 객체가 같은지 비교하고 int 형으로 리턴한다. (같으면 0, 순서상 앞에 있으면 음수, 뒤에 있으면 양수를 리턴)
- CharSequence : 해당 클래스가 문자열을 다루기 위한 클래스라는 것을 명시적으로 나타내는데 사용된다.
- String의 생성자는 매우 많다.
- 기본 생성자는 비어 있는 String 객체를 생성하지만 의미도 없고 효율적이지 못하다.
- String name = null; 이 방식이 더 효율적이다.
- 그 중 많이 사용하는 생성자는 String(byte[] byes), String(byte[] bytes, String charsetName)
- 매개 변수 byte 배열은 String 클래스의 getBytes() 메소드를 사용해 생성한다.
- 캐릭터 셋을 잘 알고 있거나, 같은 프로그램 내에서 문자열을 byte 배열로 만드는 경우 getBytes()를 사용
- 다른 시스템에서 전달 받은 문자열을 byte 배열로 변환할 때는 getBytes(Charset charset)이나 getBytes(String charsetName)을 사용한다.
- 기본 생성자는 비어 있는 String 객체를 생성하지만 의미도 없고 효율적이지 못하다.
charset
- 어떤 프로그래밍 언어를 사용할 경우에도 특수 문자(알파벳을 제외한 나라의 문자)를 표시할 일이 생기는데 특수 문자마다 고유한 캐릭터 셋을 가지고 있다.
- 한글을 처리하기 위해서 많이 사용하는 캐릭터 셋은 UTF-16, 과거에는 UTF-8이나 EUC-KR
- getBytes() 메소드와 String(byte[]) 생성자는 플랫폼의 기본 캐릭터 셋으로 변환을 한다.
- ex) 플랫폼에서 한글을 사용 중이라면 한글로 출력 시 문제가 발생하지 않는다.
- 잘못된 캐릭터 셋으로 변환을 하면 알아볼 수 없는 문자로 표시가 된다.
- 글자가 깨지는 현상을 방지하기 위해서 byte 배열로 생성할 때 사용한 캐릭터 셋을 문자열로 다시 전환할 때도 동일하게 사용해야 한다.
String korean = "한글";
byte [] array1 = korean.getBytes("UTF-16"); // byte 배열 생성 시 UTF-16으로 변환
// array1은 UTF-16으로 변환된 byte 배열이므로 문자열로 전환 시 UTF-16으로 동일하게 사용해야 한다.
String korean2 = new String(array1, "UTF-16");
- EUC-KR과 UTF-16은 한글을 바이트로 표현 시 글자 수와 상관 없이 2byte 차이가 발생한다. (UTF-16의 byte가 더 큼)
- 캐릭터 셋을 지정하는 메소드, 생성자 사용 시 try-catch로 묶어주거나 메소드 선언 시 throws 구문을 추가한다.
- 존재하지 않는 캐릭터 셋의 이름을 지정하면 UnsupportedEncodingException 예외가 발생하기 때문에
charset : 문자의 집합을 의미한다. (특정 나라의 글자를 의미)
decoding : 일반적으로 암호화되어 있거나 컴퓨터가 이해할 수 있는 값들을 알아보기 쉽게 변환하는 것.
객체 Null 체크
- 객체 null = 객체가 아무런 초기화가 되지 않았으며 클래스에 선언되어 있는 어떤 메소드도 사용할 수 없다는 의미.
- String을 포함한 어떤 객체를 사용하더라도 null 체크는 필수적이다.
- null 체크를 하지 않으면 객체에 사용할 수 있는 메소드들은 모두 예외를 발생시킨다.
- null 인 객체의 메소드에 접근하면 NullPointerException 예외를 발생시킨다.
- 객체 null 체크는 !=, == 연산자를 사용해 체크가 가능하다.
- 메소드의 매개 변수로 넘어오는 객체가 null이 될 확률이 조금이라도 있다면 반드시 확인 필요
String 클래스의 메소드
- 문자열의 길이를 확인하는 메소드 length()
- 배열도 객체긴 하지만 메소드는 없는 특수한 객체기에 배열의 크기를 확인할 때 괄호가 없는 length를 사용한다.
- 그 외 모든 클래스는 메소드를 호출해야하며 String 객체의 길이는 length() 메소드를 사용한다.
- 한글, 영어 모두 공백을 포함한 글자수의 길이를 리턴한다.
- 문자열이 비어 있는지 확인하는 메소드 isEmpty()
- boolean 타입을 리턴하는 메소드로 문자열이 비어있으면 true, 아니면 false를 리턴한다.
- 문자열에 공백만 있더라도 false를 리턴한다. (공백 != 빈칸)
String text = "check value";
String text2 = "check value"; // 값이 같으므로 Constant Pool에 의해 text에서 만든 객체를 재사용
// Constant Pool에 의해 same 출력
if(text == text2) {
System.out.println("same");
}
else {
System.out.println("different");
}
// 객체의 값이 같으므로 same 출력
if(text.equals("check value") {
System.out.println("same");
}
- 문자열이 같은지 비교하는 메소드
- equals로 시작하는 메소드, compareTo로 시작하는 메소드, contentEquals 메소드로 분류할 수 있다.
- equals() 메소드는 boolean을 리턴, compareTo() 메소드는 int를 리턴, contentEquals() 메소드는 boolean을 리턴한다.
- equals() : 객체의 값이 같으면 true, 다르면 false를 리턴한다.
System.out.println("a".equals("a")) ㅡ> true 출력 - compareTo() : 정렬을 할 때 주로 사용한다. String과 매개 변수 객체를 비교해 알파벳 순으로 앞에 있으면 음수, 뒤에 있으면 양수, 같으면 0을 리턴한다.
ex) System.out.println("a".compareTo("b")); ㅡ> -1 출력 - contentEquals() : 매개 변수로 넘어오는 CharSequence와 StringBuffer 객체가 String 객체와 같은지 비교해 같으면 true, 다르면 false를 리턴한다.
- equals() : 객체의 값이 같으면 true, 다르면 false를 리턴한다.
- equals() 메소드는 boolean을 리턴, compareTo() 메소드는 int를 리턴, contentEquals() 메소드는 boolean을 리턴한다.
- 매개 변수로 넘어온 값과 String 객체가 같은지 비교하기 위한 메소드
- 뒤에 IgnoreCase가 붙은 메소드들은 대소문자를 구분하지 않는 메소드다.
- String text = "abc"; 와 String text2 = "abc"; 의 경우 == 연산을 사용해도 true가 리턴된다.
- 객체의 값을 비교 시 == 연산자를 사용하면 객체의 값이 아닌 객체의 주소를 비교하기에 적절하지 않다.
- Constant Pool에 의해 String의 경우 동일한 값을 갖는 객체가 있으면, 이미 만든 객체를 재사용한다.
- Constant Pool에 의해 text2에서 String 객체를 생성 시 text1의 객체 값과 같기에 기존 text의 객체를 재활용하게 된다. 그렇기에 text와 text2의 객체 주소값까지도 일치하게 된다.
- 객체의 값을 비교 시 == 연산자를 사용하면 객체의 값이 아닌 객체의 주소를 비교하기에 적절하지 않다.
- String text = "abc"; 와 String text2 = new String("abc"); 의 경우 Constant Pool의 값을 재활용하지 않는다.
- new 생성자로 객체를 생성하는 경우 값이 같은 객체일지라도 재활용하지 않고 별도의 객체를 생성한다.
- equals로 시작하는 메소드, compareTo로 시작하는 메소드, contentEquals 메소드로 분류할 수 있다.
Constant Pool : 객체들을 재사용하기 위한 것으로 String의 경우 동일한 값을 갖는 객체가 있으면 이미 만든 객체를 참조(사용)한다.
- 특정 조건에 맞는 문자열이 있는지 확인하는 메소드
- startsWith(), endsWith(), contains(), matches(), regionMatches()가 있으며 boolean을 리턴한다.
- startsWith() : 가장 많이 사용하며 매개 변수로 넘겨준 값으로 시작하는지 확인한다.
- endsWith() : 매개 변수로 넘겨준 값으로 끝나는지 확인한다.
- contains() : 매개 변수로 넘겨준 값이 문자열에 존재하는지 확인한다.
- matches() : contains()와 유사하지만 매개 변수로 넘겨준 값이 정규 표현식으로 되어 있어야 한다.
- regionMatches() : 특정 영역이 매개 변수로 넘어온 문자열과 동일한지 확인한다.
- 매개 변수로 ignoreCase, toffset, other, ooffset, len이 있다.
- 매개 변수 각각의 의미는 대소문자 구분 여부, 비교 대상 문자열의 확인 시작 위치, 존재하는지 확인할 문자열, other 객체의 확인 시작 위치, 비교할 char의 개수를 나타낸다.
- startsWith(), endsWith(), contains(), matches(), regionMatches()가 있으며 boolean을 리턴한다.
정규 표현식: 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식 언어이다.
이메일 점검, 웹 URL을 점검하는 등의 작업을 쉽게 하기 위해 공식에 따라 만든 식
- String 내에서 위치를 찾아내는 메소드
- indexOf() : 해당 객체의 특정 문자열이나 char가 있는 위치(index)를 알 수 있다.
- 찾고자하는 문자열이나 char가 없으면 -1을 리턴한다.
- 모든 index는 0부터 시작한다.
- 종류는 크게 indexOf()와 lastIndexOf()로 나눠진다.
- indexOf()는 앞에서부터 찾는다
- lastIndexOf()는 뒤에서부터 찾는다.
- int를 매개 변수로 받는 경우
- char는 정수형이기에 char를 매개 변수로 넘겨주면 자동 형 변환이 일어난다.
- lastIndexOf()와 indexOf()의 매개 변수 int fromIndex는 탐색 시작 위치를 의미하는 것으로 가장 왼쪽에서부터의 위치를 의미한다.
- indexOf() : 해당 객체의 특정 문자열이나 char가 있는 위치(index)를 알 수 있다.
- String 내에서 특정 값을 추출하는 메소드
- char 단위의 값을 추출하는 메소드 charAt() 등..
- char 배열의 값을 String으로 변환하는 메소드 copyValueOf() 등...
- String의 값을 char 배열로 변환하는 메소드 toCharArray()
- 문자열의 일부 값을 잘라내는 메소드 substring(), subSequence()
- substring()은 매개 변수로 시작 인덱스를 받아서 그 부분부터 문자열의 끝까지 추출하거나 시작과 끝 인덱스 모두 매개 변수로 받을 수 있다.
- substring()은 많이 사용하는 메소드 중 하나로 indexOf()와 함께 자주 쓰인다.
- 문자열을 여러 개의 String 배열로 나누는 메소드 split()
- 문자열을 여러 개의 문자열 배열로 나누는 방법은 String 클래스의 split()과 java.util.StringTokenizer 클래스를 사용하는 방식이 있다.
- 정규 표현식을 사용하여 문자열을 나누는 경우에는 split()를 사용한다.
- 특정 String으로 문자열을 나눈다면 StringTokenizer 클래스를 사용하는 것이 편하다.
- 문자열을 여러 개의 문자열 배열로 나누는 방법은 String 클래스의 split()과 java.util.StringTokenizer 클래스를 사용하는 방식이 있다.
- String 값을 바꾸는 메소드
- 문자열을 합치는 메소드와 공백을 없애는 메소드
- concat(String str) : 매개 변수로 받은 String을 기존 문자열 우측에 붙인 새로운 문자열 객체를 생성해 리턴한다.
- concat() 메소드보다는 문자열을 +로 더하거나 StringBuffer나 StringBuilder 클래스를 사용한다.
- trim() : 문자열 맨 앞과 맨 뒤의 공백을 제거한 문자열 객체를 리턴한다.
- 작업하려는 문자열이 공백만으로 이루어진 값인지 공백을 제외한 값이 있는지 확인하기에 편리하다.
- concat(String str) : 매개 변수로 받은 String을 기존 문자열 우측에 붙인 새로운 문자열 객체를 생성해 리턴한다.
- 내용을 교체하는 메소드
- replace로 시작하는 메소드는 문자열에 있는 내용 중 일부를 변경하는 작업을 수행한다.
- 메소드를 수행한다 하더라도 기존 문자열의 값은 바뀌지 않는다.
- 변경된 값을 사용하기 위해서 해당 메소드의 리턴 값을 사용해야 한다.
- 대소문자를 구분하여 내용을 변경한다.
- 특정 형식에 맞춰 값을 치환하는 메소드
- format() 메소드는 정해진 기준에 맞춘 문자열이 있으면 그 기준에 있는 내용을 변환한다.
- %s는 String, %d는 정수형, %f는 실수형, %%는 %를 의미한다.
- 치환해야할 문자열 개수보다 매개 변수를 적게 나열하면 예외가 발생한다.
- 매개 변수를 더 많게 하는 것은 문제가 되지 않는다.
- 대소문자를 바꾸는 메소드
- toLower로 시작하는 메소드는 모두 대문자를 소문자로 변경하는 메소드
- toUpper로 시작하는 메소드는 모든 소문자를 대문자로 변경하는 메소드
- 기본 자료형을 문자열로 변환하는 메소드
- valueOf() : 매개 변수로 String으로 변환하고자 하는 기본 자료형을 명시한다.
- 기본 자료형을 String으로 변환하는 방식
- valueOf() 메소드로 변환
- 변환하고자 하는 기본 자료형에 String을 합치는 방식으로 변환
- ex) byte b = 1; String byte1 = b + " ";
- String으로 변환 후 별도의 문자열을 합치는 과정이 없는 경우 valueOf() 메소드를 사용하는 것이 좋다.
- toString()을 구현한 객체나, 정상적인 객체를 valueOf() 메소드에 넘겨주면 toString() 결과를 리턴한다.
- null인 객체의 경우 toString() 메소드를 사용할 수 없다.(NullPointerException 예외 발생)
null인 객체에 valueOf() 메소드를 사용 시 null이라는 문자열을 리턴해준다.
null이 아니면 toString() 메소드를 호출한 결과를 리턴한다.
- null인 객체의 경우 toString() 메소드를 사용할 수 없다.(NullPointerException 예외 발생)
- 절대로 사용하면 안되는 메소드
- intern() : C로 구현되어 있는 native 메소드 중 하나로 new String() 생성자를 통해 생성한 문자열 객체도 Constant Pool에 해당 값이 있으면 그 값을 참조하는 객체를 리턴하고 없으면 Pool에 값을 추가한다.
- intern() 메소드 수행 후 문자열 객체는 equals()가 아닌 ==으로 동일한지 비교할 수 있게 된다.
- equals() 보다 == 연산이 훨씬 빠르기에 성능적인 측면에서 좋지만 intern() 메소드로 억지로 Pool에 값을 할당하도록 만들면 저장 영역에 무리가 생겨 전체 자바 시스템의 성능에 악영향을 준다.
- 그렇기에 intern() 메소드는 절대 사용금지!!
- intern() : C로 구현되어 있는 native 메소드 중 하나로 new String() 생성자를 통해 생성한 문자열 객체도 Constant Pool에 해당 값이 있으면 그 값을 참조하는 객체를 리턴하고 없으면 Pool에 값을 추가한다.
- 문자열을 합치는 메소드와 공백을 없애는 메소드
StringBuffer / StringBuilder 클래스
- String은 immutable한 객체
- 한 번 만들어지면 더 이상 그 값을 바꿀 수 없다.
- String 문자열을 더하면 새로운 String 객체가 생성되고 기존 객체는 버려진다.
기존 객체는 사용할 수 없고 쓰레기가 되고 GC(가비지 컬렉션)의 대상이 된다.
- String의 단점을 보완하기 위해 나온 것이 StringBuffer, StringBuilder 클래스다.
- StringBuilder와 StringBuffer에서 제공하는 메소드가 동일하다.
- StringBuffer는 Thread safe하다.
- StringBuilder는 Thread safe하지 않다.
- 기능은 같지만 StringBuffer가 더 안전하며 StringBuilder가 더 빠르다.
- StringBuilder와 StringBuffer는 문자열을 더하더라도 새로운 객체를 생성하지 않는다.
- 더하기 기호(+) 대신 append() 메소드를 사용한다.
- append() 매개 변수로 모든 기본 자료형, 모든 참조 자료형을 포함한다.
즉 어떤 값도 매개 변수로 들어갈 수 있다. - 세미콜론이 나오기 전 계속 append()를 붙여도 상관없다.
- append() 수행 후 객체가 리턴되므로 그 객체에 계속 붙이는 작업을 해도 무방하기 때문
StringBuilder sb = new StringBuilder();
sb.append("Hello").append("world").append("!");
- JDK 5 이상에서는 String 더하기 연산을 할 경우 컴파일러가 자동으로 해당 연산을 StringBuilder로 변환해준다.
- 하나 하나 더하는 작업은 변환해 줄 필요가 없지만 for 루프와 같이 반복 연산을 할 때에는 자동으로 변환되지 않기에 변환해줘야 한다.
- String, StringBuilder, StringBuffer 공통점
- 모두 문자열을 다루는 클래스
- CharSequence 인터페이스를 구현했다.
그렇기에 세 가지 중 하나의 클래스를 사용해 매개 변수를 받는다면 String, StringBuilder 타입보다는 CharSequence 타입으로 받는 것이 좋다.
- 하나의 메소드 내에서 문자열을 생성해 더할 경우 StringBuilder를 사용해도 괜찮다.
- 어떤 클래스에 문자열을 생성하여 더하기 위한 문자열을 처리하기 위한 인스턴스 변수가 선언되고 여러 쓰레드에서 이 변수를 동시에 접근하는 경우 반드시 StringBuffer를 사용해야 한다.
간단 내용 정리
1. String 클래스는 final 클래스인가요? 만약 그렇다면, 그 이유는 무엇인가요?
ㅡ> O, 더 이상 다른 클래스에서 확장하지 못하게 하기 위함
2. String 클래스가 구현한 인터페이스에는 어떤 것들이 있나요?
ㅡ> Serializable, Comparable, CharSequence
3. String 클래스의 생성자 중에서 가장 의미없는 (사용할 필요가 없는) 생성자는 무엇인가요?
ㅡ> 기본 생성자, 새로운 값이 할당되자마자 GC의 대상이 되어버리기 때문에
4. String 문자열을 byte 배열로 만드는 메소드의 이름은 무엇인가요?
ㅡ> getBytes()
5. String 문자열의 메소드를 호출하기 전에 반드시 점검해야 하는 사항은 무엇인가요?
ㅡ> String 객체가 null인지 체크해야한다.
6. String 문자열의 길이를 알아내는 메소드는 무엇인가요?
ㅡ> length()
7. String 클래스의 equals() 메소드와 compareTo() 메소드의 공통점과 차이점은 무엇인가요?
ㅡ> 공통점으로는 문자열을 비교한다는 점
차이점은 equals()는 같으면 true, 다르면 false로 boolean 타입을 리턴해주고 compareTo()는 같으면 0, 다를땐 객체가 매개 변수의 객체보다 순서가 앞이면 음수를, 순서가 뒤라면 양수로 int 타입을 리턴해준다.
8. 문자열이 "서울시"로 시작하는지를 확인하려면 String의 어떤 메소드를 사용해야 하나요?
ㅡ> startsWith()
9. 문자열에 "한국"이라는 단어의 위치를 찾아내려고 할 때에는 String의 어떤 메소드를 사용해야 하나요?
ㅡ> contains()나 matches()는 단어의 존재 여부를 확인할 수 있고 indexOf()는 단어의 위치(index)를 알 수 있다.
10. 위의 문제의 답에서 "한국"이 문자열에 없을 때 결과값은 무엇인가요?
ㅡ> contains(), matches()는 false를 리턴하고 indexOf()는 -1을 리턴한다.
11. 문자열의 1번째부터 10번째 위치까지의 내용을 String으로 추출하려고 합니다. 어떤 메소드를 사용해야 하나요?
ㅡ> substring(), subSequence()
12. 문자열의 모든 공백을 * 표시로 변환하려고 합니다. 어떤 메소드를 사용하는 것이 좋을까요?
ㅡ> replaceAll()
13. String의 단점을 보완하기 위한 두개의 클래스는 무엇인가요?
ㅡ> StringBuffer, StringBuilder
14. 문제의 답에서 문자열을 더하기 위한 메소드의 이름은 무엇인가요?
ㅡ> append()