자바-16(문자열)
학습할 것 (필수)
String 이란?
String 활용
StringBuffer,StringBuilder
String 이란?
- 변경 불가능한(immutable) 클래스이다.
- 문자열은 문장을 뜻한다 (ex: "JAVA" ,"A" , "Hello")
- 문자열은 문자의 집합이므로 char 타입의 배열과 같다
- 자바에서 문자열에 해당하는 자료형은 String이다.
char data[] = {'a', 'b', 'c'};
String data1 ="abc";
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
- char data[] = String data1
- String 클래스는 문자열을 저장하기 위해서 문자형 배열변수(char[] value)를 인스턴스 변수로 정의해놓고 있다.
- 인스턴스 생성시 생성자의 매개변수로 입력되는 문자열은 이 인스턴스 변수(value)에 문자열 배열(char[])로 저장되는 것이다.
String a ="Happy day";
String b ="a";
String c = "123";
- 위와 같이 문자열을 정의한다.
- 하지만, String은 클래스이고 이를 사용하려면 아래와 같이 객체를 생성해야한다.
char data[] = {'a', 'b', 'c'};
String i = new String(data);
String a = new String("Happy day");
String b = new String("a");
String c = new String("123");
- 하지만, String은 프로그램 이곳저곳 어디서나 사용하기 때문에 편의를 위해 new 연산자를 사용하지 않고 객체생성을 할 수 있다.
- 첫번째 방식으로 표현하면 가독성에 이점이 있고 컴파일 시 최적화에 도움을 주기 때문에 첫번째 방식으로 사용하자.
- 한번 생성된 String 인스턴스가 갖고 있는 문자열은 읽어 올 수만 있고, 변경할 수는 없다.
- 예를 들어,
+
연산자를 이용해서 문자열을 결합하는 경우 인스턴스내의 문자열이 바뀐느 것이 아니라 새로운 문자열이 담긴 String 인스턴스가 생성되는 것이다.
- 덧셈연사자를 사용해서 문자열을 결합하는 것은 매 연산시 마다 새로운 문자열을 가진 String 인스턴스가 생성디ㅗ어 메모리공간을 차지하게 되므로 가능한 결합횟수를 줄이는 것이 좋다.
char data[] = {'a', 'b', 'c'};
String data1 ="abc";
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
String a ="Happy day";
String b ="a";
String c = "123";
char data[] = {'a', 'b', 'c'};
String i = new String(data);
String a = new String("Happy day");
String b = new String("a");
String c = new String("123");
+
연산자를 이용해서 문자열을 결합하는 경우 인스턴스내의 문자열이 바뀐느 것이 아니라 새로운 문자열이 담긴 String 인스턴스가 생성되는 것이다.- String은 primitive type이 아니지만, 자바에서는 primitive type처럼 리터럴 표현식을 사용할수있게 해준다.
- String은 메모리에 저장된 리터럴의 주소를 저장하고 있다
- 문자열이 변경되면 기존의 객체를 버리고 새로운 객체를 메모리에 생성한다.
- 기존 객체는 GC에 의해서 메모리 회수가 이루어진다.
- String을 사용하여 문자열의 변경을 하면 기존객체가 GC에 의해 메모리회수가 바로 일어나는 것이 아니기 때문에 메모리의 낭비가 있고, 새로운 객체에 기존 객체를 복사하는 오버헤드도 발생한다.
- 많은 데이터의 IO가 발생하는 극한 상황이라고 가정하면 위 문제를 고려해야한다.
- 문자열을 다루는 작업이 많이 필요한 경우네는 String 클래스 대신 StringBuffer 클래스를 사용하는 것이 좋다. StringBuffer 인스턴스에 저장된 문자열은 변경이 가능하므로 하나의 StringBuffer 인스턴스만으로도 문자열이 다루는것이 가능하다.
문자열 리터럴
- 자바소스파일에 포함된 모든 문자열 리터럴은 컴파일 시에 클래스 파일에 저장된다.
- 이 때 같은 내용의 문자열 리터럴은 한번만 저장된다.
- 문자열 리터럴도 String 인스턴스 이고 한번 생성하면 내용을 변경할수없기 때문에 하나의 인스턴스를 공유하면 되기 때문이다.
- String 리터럴들은 컴파일 시에 클래스파일에 저장된다.
- 클래스 파일에는 소스파일에 포함된 모든 리터럴의 목록이 있다.
- 해당 클래스 파일이 클래스 로더에 의해 메모리에 올라갈 때, 이 리터럴의 목록이 있는 리터럴들이 JVM 내에 있는 상수 저장소(constant pool)에 저장된다.
빈 문자열
- 길이가 0인 배열이 존재 할 수 있다.
- char형 배열도 길이가 0인 배열을 생성할 수있고, 이 배열을 내부적으로 가지고 있는 문자열이 바로 빈 문자열이다.
String s=""
와 같은 문장이 있을때, 참조변수 s가 참조하고 있는 String 인스턴스는 내부에new Char[0]
와 같이 길이가 0인 char형 배열을 저장하고 있는 것이다.- 그러나
String s=""
과 같은 표현이 가능하다고 해서char c='';
와 같은 표현이 가능한 것은 아니다. char형 변수에는 반드시 하나의 문자를 지정해야 하낟. - 일반적으로 변수를 선언할때, 각 타입의 기본값으로 초기화하지만 String은 참조형 타입의 기본값인 null보다는 빈 문자열로, char형인 기본값은 ‘₩u0000’ 대신 공백으로 초기화 하는 것이 보통이다. (‘₩u0000’은 유니코드의 첫 번째 문자로써 아무런 문자도 지정되지 않은 빈 문자이다.)
String 활용:
1.문자열을 비교
compareTo
StringCompareEx
package me.whiteship.livestudy.string;
public class StringCompareEx {
public static void main(String[] args) {
String str ="Hello World";
String str1 = "hfllo World";
Object obj = str;
System.out.println(str.compareTo(str1));
System.out.println(str.compareToIgnoreCase(str1));
System.out.println(str.compareTo(obj.toString()));
}
}
output
-32
-1
0
- 문자열 간에 아스키코드값 차이를 리턴한다. 리턴값이 0이면 같은 문자열을 가진다.
Equals
equals
package me.whiteship.livestudy.string;
public class StringEqualsEx {
public static void main(String[] args) {
String s1= "hello";
String s2= "hello";
String s3= new String("hello");
String s4 = new String("Hello");
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));
System.out.println(s1.equals(s4));
}
}
output
true
true
false
- 결과로 boolean을 리턴한다. 같으면 true, 다르면 false
==
package me.whiteship.livestudy.string;
public class StringEqualsEx {
public static void main(String[] args) {
String s1= "hello";
String s2= "hello";
String s3= new String("hello");
String s4 = new String("Hello");
System.out.println(s1==s2);
System.out.println(s1==s2);
System.out.println(s1==s4);
}
}
output
true
true
false
- 결과로 boolean을 리턴한다. 같으면 true, 다르면 false
2. 문자열 내에서 지정된 문자열의 마지막을 검색
인스턴스.lastIndexOf(Stringname)
package me.whiteship.livestudy.string;
public class SearchLastString {
public static void main(String[] args) {
String str = "Hello world, Hello hi, Hello hihihi";
int lastIndex = str.lastIndexOf("Hello");
if(lastIndex==-1){
System.out.println("Hello not found");
}else{
System.out.println(lastIndex);
System.out.println(str.charAt(lastIndex));
}
}
}
output
23
H
- lastIndexOf("Hello")는 문자열에 포함된 여러 "Hello" 들중 가장 뒤쪽에 위치한 문자열의 시작 인덱스를 리턴한다.
3. 문자열에서 지정된 문자를 삭제
- substring()을 이용
package me.whiteship.livestudy.string;
public class StringExample {
public static void main(String[] args) {
String str = "Hello World, Hello JAVA";
System.out.println(str);
System.out.println(str.charAt(6));
System.out.println(removeChatAt(str,6));
}
public static String removeChatAt(String s, int pos){
return s.substring(0,pos)+s.substring(pos+1);
}
}
output
Hello World, Hello JAVA
W
Hello orld, Hello JAVA
- deleteChatAt()을 이용
public class RemoveCharacter
{
public static void main(String[] args)
{
StringBuilder MyString = new StringBuilder("Hello World");
System.out.println("The string before removing character: " + MyString);
MyString = MyString.deleteCharAt(5);
System.out.println("The string after removing character: " + MyString);
}
}
output
The string before removing character: Hello World
The string after removing character: HelloWorld
4. 문자열의 하위 문자열을 변경
replace 이용
package me.whiteship.livestudy.string;
public class StringExample {
public static void main(String[] args) {
String str = "Hello World, Hello JAVA";
System.out.println(str.replace("H","F"));
System.out.println(str.replaceFirst("Hello","bye"));
System.out.println(str.replaceAll("Hello","bye"));
}
}
output
Fello World, Fello JAVA
bye World, Hello JAVA
bye World, bye JAVA
- replace는 문자열에 포함된 문자를 다른 문자로 replace
- replaceFirst는 문자열에 포함된 특정 문자열 중 가장 앞에 위치한 문자열을 다른 문자열로 변경
- replaceAll은 문자열에 포함된 특정 문자열 전체를 다른 문자열로 변경
5. 문자열 뒤집기
- StringBuffer(String str)을 통해 입력 문자열을 버퍼링 및 반전시켜 문자열로 변환
package me.whiteship.livestudy.string;
public class StringExample {
public static void main(String[] args) {
String str = "Hello World, Hello JAVA";
String str1 = new StringBuffer(str).reverse().toString();
System.out.println(str);
System.out.println(str1);
}
}
output
Hello World, Hello JAVA
AVAJ olleH ,dlroW olleH
- 매개변수에서 문자열(str)을 반목문을 통해 거꾸로 출력
package me.whiteship.livestudy.string;
public class StringExample {
public static void main(String[] args) {
String str = "Hello World, Hello JAVA";
char[] str1 = str.toCharArray();
for (int i = str1.length-1; i >=0; i--) {
System.out.println(str1[i]);
}
}
}
output
AVAJ olleH ,dlroW olleH
6. 문자열에서 문구검색
- 문자열에서 단어의 위치값을 반환하는 indexOf를 사용해서 단어를 검색
- 검색결과 없을 경우 -1을 반환
package me.whiteship.livestudy.string;
public class StringExample {
public static void main(String[] args) {
String str = "Hello World, Hello JAVA";
int idx = str.indexOf("Hello");
if(idx==-1){
System.out.println("Hello not found");
}else{
System.out.println(idx);
System.out.println(str.charAt(idx));
}
}
}
output
0
H
- String 객체에서 contains를 통해 단어를 검색
package me.whiteship.livestudy.string;
public class StringExample {
public static void main(String[] args) {
String str = "Hello World, Hello JAVA";
System.out.println(str.contains("JAVA"));
}
}
output
true
7. 문자열을 여러개의 하위 문자열로 나누기
- split(string)을 통해 문자열 및 구분자(-,\.)로부터 여러 하위 문자열로 분할
- 구분자가 공백의 경우 \s 를 사용
package me.whiteship.livestudy.string;
public class StringExample {
public static void main(String[] args) {
String str = "Hello-World-Hello-JAVA";
String [] tmp;
String [] tmp1;
String delimeter="-";
tmp = str.split(delimeter);
for (int i = 0; i < tmp.length; i++) {
System.out.println(tmp[i]);
}
System.out.println();
str = "max.min.avg.sum";
delimeter="\\.";
tmp1=str.split(delimeter);
for (int i = 0; i < tmp1.length; i++) {
System.out.println(tmp1[i]);
}
}
}
output
Hello
World
Hello
JAVA
max
min
avg
sum
8. 문자열을 대문자로 변환
- String 클래스의 toUpperCase를 통해 대문자로 변경
package me.whiteship.livestudy.string;
public class StringExample {
public static void main(String[] args) {
String str = "Hello-World-Hello-JAVA";
String str1 = str.toUpperCase();
System.out.println(str);
System.out.println(str1);
}
}
output
Hello-World-Hello-JAVA
HELLO-WORLD-HELLO-JAVA
9. 문자열의 영역을 일치확인
- regionMatches 를 통해 두 문자열의 영역이 일치 확인
- 해당 전달 인자에 대한 설명
- 1: 비교가 시작되는 문자열의 인덱스
- 2: 대상 문자열
- 3: 비교가 시작되는 대상문자열의 인덱스
- 4: 비교할 문자수
package me.whiteship.livestudy.string;
public class StringExample {
public static void main(String[] args) {
String str = "Hello-World-Hello-JAVA";
String str1 = "Hel4o-World-Hello-PYTHON";
boolean match = str.regionMatches(str.indexOf("World"),str1,str1.indexOf("World"),3);
System.out.println(match);
match = str.regionMatches(str.indexOf("Hello"),str1,str1.indexOf("Hel4o"),3);
System.out.println(match);
match = str.regionMatches(str.indexOf("Hello"),str1,str1.indexOf("Hel4o"),4);
System.out.println(match);
}
}
output
true
true
false
10. 두 문자열의 생성 성능 비교
- String literals VS String objects
package me.whiteship.livestudy.string;
public class StringExample {
public static void main(String[] args) {
//String str1 = "Hello-World-Hello-JAVA";
//String str2 = "Hello-World-Hello-JAVA";
long start = System.currentTimeMillis();
for (int i = 0; i < 50_000; i++) {
String str1 = "Hello-World-Hello-JAVA";
String str2 = "Hello-World-Hello-JAVA";
}
long end = System.currentTimeMillis();
System.out.println(end-start+" milli sec");
start = System.currentTimeMillis();
for (int i = 0; i < 50_000; i++) {
String str3 = new String("Hello-World-Hello-JAVA");
String str4 = new String ("Hello-World-Hello-JAVA");
}
end = System.currentTimeMillis();
System.out.println(end-start+" milli sec");
}
}
output
2 milli sec
8 milli sec
11. 문자열 생성 최적화
- literals와 new String 및 String.intern을 통해 문자열을 생성
package me.whiteship.livestudy.string;
public class StringExample {
public static void main(String[] args) {
//String str1 = "Hello-World-Hello-JAVA";
//String str2 = "Hello-World-Hello-JAVA";
String[] strings = new String[50_000];
for (int i = 0; i < strings.length; i++) {
strings[i] = "s"+i;
}
long start = System.currentTimeMillis();
for (int i = 0; i < strings.length; i++) {
strings[i] = "hello";
}
long end = System.currentTimeMillis();
System.out.println(end-start + " ms");
start = System.currentTimeMillis();
for (int i = 0; i < strings.length; i++) {
strings[i] = new String("hello");
}
end = System.currentTimeMillis();
System.out.println(end-start + " ms");
start = System.currentTimeMillis();
for (int i = 0; i < strings.length; i++) {
strings[i] = new String("hello");
strings[i] = strings[i].intern();
}
end = System.currentTimeMillis();
System.out.println(end-start + " ms");
}
}
output
1 ms
4 ms
9 ms
12. 문자열 포맷
- format 이용
package me.whiteship.livestudy.string;
import java.util.Locale;
public class StringExample {
public static void main(String[] args) {
String str1 = "Hello-World-Hello-JAVA";
String str2 = "Hello-World-Hello-JAVA";
double e =Math.E;
System.out.format("%f%n",e);
System.out.format(Locale.GERMANY, "%-10.4f%n%n",e);
}
}
output
2.718282
2,7183
13. 두 줄을 연결
- 연산자 및 StringBuffer.append 를 사용하여 문자열 연결
package me.whiteship.livestudy.string;
import java.util.Locale;
public class StringExample {
public static void main(String[] args) {
String str1 = "Hello-World-Hello-JAVA";
String str2 = "Hello-World-Hello-JAVA";
System.out.println(str1+str2);
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(str1);
stringBuffer.append(str2);
System.out.println(stringBuffer);
}
}
output
Hello-World-Hello-JAVAHello-World-Hello-JAVA
Hello-World-Hello-JAVAHello-World-Hello-JAVA
14. 문자열 유니코드
- codePointAt 을 이용하여 지정된 인덱스에 해당하는 문자의 유니코드를 구한다.
package me.whiteship.livestudy.string;
public class StringExample {
public static void main(String[] args) {
String str1 = "Hello-World-Hello-JAVA";
String str2 = "Hello-World-Hello-JAVA";
System.out.println(str1.codePointAt(0));
}
}
output
72
15. 문자열 공백없애기
- trim 을 이용하여 문자열의 시작과 끝에 있는 공백을 없애준다. 중간 공백은 없애주지 않는다.
String str = " h E L L O ";
System.out.println(str.trim());
output
h E L L O
16. 문자열 합치기
- concat() 을 이용하여 문자열을 이어준다
package me.whiteship.livestudy.string;
public class StringExample {
public static void main(String[] args) {
String str1 = "Hello-World-Hello-JAVA123";
String str2 = "Hello-World-Hello-JAVA";
System.out.println(str1.concat(str2));
}
}
output
Hello-World-Hello-JAVA123Hello-World-Hello-JAVA
17. 문자열 중 특정문자열 추출
- substring을 이용
package me.whiteship.livestudy.string;
public class StringExample {
public static void main(String[] args) {
String str1 = "Hello-World-Hello-JAVA123";
String str2 = "Hello-World-Hello-JAVA";
System.out.println(str1.substring(0,5));
System.out.println(str1.substring(6));
}
}
output
Hello
World-Hello-JAVA123
18. 문자 인코딩 변환
- getBytes(String charsetName)을 사용하면, 문자열의 문자 인코딩을 다른 인코딩으로 변경할 수 있다.
- 자바가 UTF-16을 사용하지만. 문자열 리터럴에 포함되는 문자들은 OS의 인코딩을 사용한다.
byte[] str = "가".getBytes("UTF-8"); // 문자열을 UTF-8로 변환
String str = new String(str, "UTF-8"); // byte 배열을 문자열로 변환
- 서로 다른 문자 인코딩을 사용하는 컴퓨터 간에 데이터를 주고받을 때는 적절한 문자 인코딩이 필요하다.
- UTF-8은 한글 한 글자를 3byte로 표현하고 , CP249는 2byte로 표현한다.
19. 기본형을 String으로 변환
- 기본형을 문자열로 변경하는 방법은 간단하다.
- 숫자에 빈 문자열""을 더해주기만 하면된다.
- 이 외에도 valueOf()을 사용하는 방법도 있다.
- 성능은 valueOf()가 더 좋지만, 빈 문자열을 더하는 방법이 간단하고 편하기 때문에 성능향상이 필요한 경우메나 valueOf()를 써보자.
int i = 10;
String s= String.valueOf(i);
System.out.println(s);
int i = 10;
String s = i+"";
System.out.println(s);
20. String을 기본형 값으로 변환
- 이전에는 parseInt()와 같은 메서드를 많이 사용했었는데, 메서드의 이름을 통일하기 위해 valueOf() 메서드가 나중에 추가되었다.
- valueOf(String s) 는 메서드 내부에서 그저 parseInt(String s)를 호출한다.
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
- 두 메서드는 반환타입만 다르지 같은 메서드이다.
String s= "10";
int i = Integer.valueOf(s);
System.out.println(i);
StringBuffer,StringBuilder
- String 클래스의 단점을 보완하기 위해 나온 클래스들이다.
- String 클래스는 인스턴스를 생성할때 지정한 문자열을 변경할 수 없지만 StringBuffer 클래스는 변경이 가능하다.
- 내부적으로 문자열 편집을 위한 버퍼(buffer)를 가지고 있으며, StringBuffer 인스턴스를 생성할때 그 크기를 지정할수있다.
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
private transient char[] toStringCache;
- StringBuffer 클래스는 String 클래스와 같이 문자열을 저장하기 위한 char형 배열의 참조변수 인스턴스로 선언해 놓고 있다.
- StringBuffer 인스턴스가 생성될때,char형 배열이 생성되며 이 때 생성된 char형 배열을 인스턴스변수 value가 참조하게 된다.
- String과 달리 데이터가 변경되어도 기존 객체를 재활용하기 때문에 데이터 변경면에서는 String보다 빠르다.
- 대체적으로 String과 매우 흡사하다.
- 극한 상황이 아니라면 아무거나 사용해도 상관없다.
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
private transient char[] toStringCache;
StringBuffer의 생성자
-
StringBuffer 클래스의 인스턴스를 생성할 때, 적절한 길이의 char형 배열이 생성되고 , 이 배열은 문자열을 저장하고 편집하기 위한 공간(buffer)로 사용된다.
-
StringBuffer 인스턴스를 생성할때는 생성자 StringBuffer(int length)를 사용해서 StringBuffer 인스턴스에 저장될 문자열의 길이를 고려하여 충분히 여유 있는 크기로 지정하는 것이 좋다.
-
StringBuffer 인스턴스를 생성할 때, 버퍼의 크기를 지정해 주지 않으면 16개의 문자를 저장할 수 있는 크기의 버퍼를 생성한다.
public StringBuffer(int length) {
value = new char[length];
shared = false;
}
public StringBuffer() {
this(16);
}
public StringBuffer(String str) {
this(str.length() + 16);
append(str);
}
-
StringBuffer 인스턴스로 문자열을 다루는 작업을 할때, 버퍼의 크기가 작업하려는 문자열의 길이보다 작을때는 내부적으로 버퍼의 크기를 증가시키는 작업이 수행된다.
-
배열의 길이는 변경될수없으므로 새로운 길이의 배열을 생성한후에 이전 배열의 값을 복사해야한다
StringBuffer의 비교
- String 클래스에서는 equals 메서드를 오버라이딩해서 문자열의 내용을 비교하도록 구현되어있지만, StringBuffer 클래스는 equals 메서드를 오버라이딩하지 않아서 StringBuffer 클래스의 equals 메서드를 사용해도 등가비교연산자(==)로 비교한 것과 같은 결과를 얻는다.
StringBuffer sb = new StringBuffer("abc");
StringBuffer sb2 = new StringBuffer("abc");
System.out.println(sb == sb2); // false
System.out.println(sb.equals(sb2)); // false
- 반면에 toString()은 오버라이딩되어있어서 StringBuffer 인스턴스에 toSting()을 호출하면, 담고잇는 문자열을 String으로 변환한다.
- 그래서 StringBuffer 인스턴스에 담긴 문자열을 비교하기 위해서는 StringBuffer 인스턴스에 toString()을 호출해서 String 인스턴스를 얻은 다음에, 여기에 equals 메서드를 사용해서 비교해야 한다.
String Builder란?
- StringBuffer는 멀티쓰레드에 안전(thread safe)하도록 동기화되어있다.
- 멀티쓰레드로 작성된 프로그램이 아닌경우, StringBuffer의 동기화는 불필요하게 성능만 떨어뜨리게 된다.
- 그래서 StringBuffer에서 쓰레드의 동기화만 뺀 StringBuilder가 새로 추가되었다.
참고
Author And Source
이 문제에 관하여(자바-16(문자열)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@yyong3519/자바-16문자열저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)