카테고리 없음

[Java] String

songsua 2025. 1. 10. 14:53

기본형은 char 은 문자 하나를 다룰 때 사용한다.

char을 사용해서 여러 문자를 나열하면 char[]을 사용해야 한다. 

package string;

public class charArrayMain {
    public static void main(String[] args) {
        char[] charArr; = new char[]{'h', 'e', 'l', 'l', 'o'};
    }
}

 

이런식으로 사용하는 것은 불편하기 때문에 문자열을 매우 편리하게 다룰 수 있는 String 클래스를 사용한다.

package string;

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

    System.out.println(str1);
    System.out.println(str2);
    System.out.println(str3);
    }
}

 

  •  " " : 쌍따옴표를 사용하여 string 사용한다
  • new String("Hello") : 객체를 생성하여 string 을 사용한다.

"" 을 사용할 때는 String 이 클래스이며, 참조형 객체를 사용하여 String 인스턴스의 참조값만 들어가서 사용하는 것이다.

 

String 을 비교할때는 "==" 이 아니라 equals() 비교를 해야한다.

동일성 : == 연산자를 사용해서 동일한 객체를 가리키고 있는지 확인한다.

동등성 : equeals() 메서드를 사용하여 두 객체가 논리적으로 같은지 확인한다.

package string;

public class Equals {
    public static void main(String[] args) {
        String str1 = new String("abc");
        String str2 = new String("abc");
        System.out.println("new String() == 비교: " + (str1 == str2));
        System.out.println("str1.equals(str2): " + str1.equals(str2));


        String str3 = "abc";
        String str4 = "abc";
        System.out.println("str3.equals(str4): " + (str3.equals(str4)));
        System.out.println("str3 == str4:" + (str3 == str4) );
    }
}

 

new String() == 비교: false
str1.equals(str2): true
str3.equals(str4): true
str3 == str4:true

 

"==" 은 false로 출력되는 것을 알 수 있다.

 

String str1 = new String("abc");  // 참조값 x001
String str2 = new String("abc");  // 참조값 x002  이기 때문에 
System.out.println("new String() == 비교: " + (str1 == str2)); // == 해도 값이 다르고 나온다

equals 에서는 overriding 을 해놨기 때문에 참조값으로 비교하는 것이 아닌, 문자열 자체를 비교한다.

 

String str3 = "abc";
String str4 = "abc";
System.out.println("str3.equals(str4): " + (str3.equals(str4)));
System.out.println("str3 == str4:" + (str3 == str4) );

 

그렇다면 왜 str3, str4(리터널비교)에서는 == 했는데 True 가 나올 까?

리터널을 사용할 경우에는 메모리 효율성과 성능 최적화를 위해 문자열 풀을 사용한다.

자바는 클래스에 문자열 리터럴이 있을 경우에 String 인스턴스를 미리 만들어 둔다.

이때 같은 문자열이 있으면 중복해서 만들지는 않는다.

위의 예시처럼 "abc" 라는 문자를 가진 String 인스턴스를 찾고 그 인스턴스의 참조를 반환한다.

하지만 "==" 를 사용하면 안되는 이유는 서로 다른 개발자가 있을 때, 가져오는 문자열이 String pool 에서 가져오는지

다른 인스턴스의 참조값을 가져오는 지 등 알 수 가 없다.

그렇기 때문에 문자열 비교를 할때는 무조건 equals 를 사용하는 것이 좋다.

 

String의 경우 불변인데, 불변이기 때문에 String 클래스에 단점이 존재한다.

불변이기 때문에 기존에 있는 객체를 수정하지 않고 새로운 객체를 생성하여 값을 변경하는데,

이럴 경우 객체가 많아질때마다 계속해서 새로운 객체를 생성해야한다는 점이 단점이다.

 

이러한 상황이면 더 많은 String 객체를 만들고 GC를 해야 한다. 

 

StringBuilder

이러한 문제를 해결하기 위해서는 불변이 아닌 가변 String 이 존재하면 되는 것이다.

 

package lang.string.builder;
 public class StringBuilderMain1_1 {
     public static void main(String[] args) {
         StringBuilder sb = new StringBuilder();
         sb.append("A");
         sb.append("B");
         sb.append("C");
         sb.append("D");
         System.out.println("sb = " + sb);
         sb.insert(4, "Java");
         System.out.println("insert = " + sb);
        sb.delete(4, 8);
        System.out.println("delete = " + sb);
        sb.reverse();
        System.out.println("reverse = " + sb);  //StringBuilder -> String
        String string = sb.toString();
        System.out.println("string = " + string);
    }
}

 

  • `StringBuilder` 객체를 생성한다.
  • `append()` 메서드를 사용해 여러 문자열을 추가한다.
  • `insert()` 메서드로 특정 위치에 문자열을 삽입한다. `delete` () 메서드로 특정 범위의 문자열을 삭제한다.
  • `reverse()` 메서드로 문자열을 뒤집는다.
  • 마지막으로 `toString` 메소드를 사용해 `StringBuilder` 의 결과를 기반으로 `String` 을 생성해서 반환한다.

StringBuilder를 직접 사용하는 것이 더 좋은 경우

  • 반복문에서 반복해서 문자를 연결할 때
  • 조건물을 통해 동적으로 문자열을 조합할 때
  • 복잡한 문자열의 특정 부분을 변경해야 할 때
  • 매우 긴 대용량 문자열을 다룰 때

메서드 체인닝

단순히 값을 누적해서 더하는 기능을 제공하는 클래스이다.

package string;

public class ValueAdder {
    private int value;

    //본인의 값을 증가 시켜주는 메서드 자기자신(this) 을 참조 값으로 반환한다.
    public ValueAdder add(int addValue) {
        value += addValue;
        return this;
    }

    public int getValue() {
        return value;
    }

}

 

package string;

public class MethodChainMain1 {
    public static void main(String[] args) {
        ValueAdder adder = new ValueAdder();
        adder.add(1);
        adder.add(2);
        adder.add(3);


        int result = adder.getValue();
        System.out.println(result);
    }
}

 

add() 는 return this 을 사용하기 때문에 자기 자신의 참조값을 반환한다. 

따라서 adder, adder1, adder2, adder3  모두 같은 참조값을 사용한다. 

 

package string;

public class MethodChainMain3 {
    public static void main(String[] args) {
        ValueAdder adder = new ValueAdder();
        adder.add(1).add(2).add(3).getValue();
        
        int result = adder.getValue();
        System.out.println(result);
    }
}

 . 을 사용하여 체인처럼 묶인 것을 메서드 체이닝 이라고 한다.

adder.add(1).add(2).add(3).getValue() //value=0
x001.add(1).add(2).add(3).getValue() //value=0, x001.add(1)을 호출하면 그 결과로 x001
을 반환한다.
x001.add(2).add(3).getValue() //value=1, x001.add(2)을 호출하면 그 결과로 x001을 반환한
다.
x001.add(3).getValue() //value=3, x001.add(3)을 호출하면 그 결과로 x001을 반환한다.
 x001.getValue() //value=6
6

 

메서드 체이닝은 메서드가 끝나는 시점에 바로 . 찍어서 변수명을 생략할 수 있다.

 

참고로 자바의 라이브러리와 오픈 소스들은 메서드 체이닝 방식을 종종 사용한다.

 

문제와풀이

IndexOf()

str에서 ".txt" 문자열이 언제부터 시작하는 지 위츠를 찾아서 출력해라. indexof()사용해라

package string.test;

public class TestString3 {
    public static void main(String[] args) {
        String str1 = "Hello.txt";
        int idx = str1.indexOf(".txt");
        System.out.println(idx);
    }
}

 

Substring() 

substring()을 사용해서 hello 부분과 .txt 부분을 분리하여라 

package string.test;

public class TestString4 {
    public static void main(String[] args) {
        String str1 = "Hello.txt";
        String idx = str1.substring(0, 5);
        System.out.println(idx);
    }
}

 

 

둘이 잘 혼합하여 사용해보기

package string.test;

public class TestString5 {
    public static void main(String[] args) {
        String str1 = "Hello.txt";
        String str2 = ".txt";

        int extindx = str1.indexOf(str2);
        System.out.println(extindx);
        String filename = str1.substring(0, extindx);
        System.out.println("filename : " + filename);
        String filename1 = str1.substring(extindx);
        System.out.println("extname : " + filename1);
    }
}

 

5
filename : Hello
extname : .txt

 

 

검색 count

str 에서 key로 주어지는 문자를 찾고, 찾은 문자의 수를 출력해라.

package string.test;

public class TestString6 {
    public static void main(String[] args) {
        String str = "start hello java, hello jpa index hello " ;
        String key = "hello";
        int count = 0;
        int index = str.indexOf(key);
        System.out.println("Index : " + index);
        while (index >= 0) {
           index = str.indexOf(key, index + 1);
            count++;
        }

        System.out.println("count : " + count);
    }

}

 

 

공백제거

package string.test;

public class TestString7 {
    public static void main(String[] args) {
        String str1 = "    Hello Java.    ";
        String trim = str1.trim();  //strip 도 가능
        System.out.println("trim = " + trim);
    }
}

 

 

Replace 사용하기

package string.test;

public class TestString7 {
    public static void main(String[] args) {
        String str1 = "    Hello Java.    ";
        String result = str1.replace("Java", "jvm");
        System.out.println(result);
    }
}