[java] 文字列の扱い方まとめ

javaにおける文字列の扱い方をまとめる。

まず文字列の型について記述し、String型の基本操作をまとめ、最後にStringBuilderを用いた文字列操作についてまとめる。

### 文字列の型
#### String型の特徴

String型は、イミュータブル（不変）である。
つまり、操作によって文字列を連結したり、切り出したりすると、その文字列自体が変化するのではなく、記憶領域に新たな文字列が作成される。
これにより、以下のような特徴がある。

- 破壊変更が起きないため、プログラムの保守性が向上する
- プログラムの見通しが立ちやすくなる
- メモリ効率が悪い
- メソッドで出来る文字列操作が限られる

#### StringBufferとStringBuilder

この効率の悪さや操作のしづらさを解決するのがミュータブル（可変）なStringBuilderクラス・StringBufferクラスである。

StringBuilderとStringBufferは使い方が同じであり、違いはStringBufferはスレッドセーフで、StringBuilderはスレッドセーフでないという点のみである。
スレッドセーフとは、あるコードを複数のスレッドが同時並行的に処理した場合に問題が発生しないことを意味する言葉である。

したがって、マルチスレッド処理を行わない場合は、同期処理を行わない分処理が早いStringBuilderを使用した方が良いと言える。
使い方については後述する。

### String型の基本操作
以下のString型文字列Sについて基本操作を行う。

```java
String str = "a,b,c";
```
#### 長さの取得
文字列の長さを取得する。
戻り値はint型。

```java
str.length()
```

#### N文字目の取得
戻り値はchar型。

```java
str.charAt(int index)
```

#### 文字列を結合する
+で文字列の結合ができる。

```java
str += "String型文字列"
```

#### 文字列を分割する
文字列を指定した区切り文字で分割する。
区切り文字を""とすれば1文字ずつ分割する。
戻り値はString型配列。

```java
str.split("区切り文字")
```

#### 文字列を切り出す
endIndexは省略可能。
指定する場合は、endIndexは含まれないことに注意する。
戻り値はString型。

```java
str.substring(int beginIndex, int endIndex)
```

#### 文字列比較
String型は同じ文字列でも参照値が異なる場合があるので、pythonのように==で比較することができない。
戻り値はboolean。

```java
str.equals("String型文字列")
```

IgnoreCaseをつけると大文字・小文字を無視して比較可能。

```java
str.equalsIgnoreCase("String型文字列")
```

#### 辞書順比較
比較する文字列がstrと比べてどれだけ前にあるかを数値で返す。
つまり、比較する文字列がstrより後なら負の値を、前なら正の値を、一致するなら0を返す。
戻り値はint型。

```java
str.compareTo("String型文字列")
"a".compareTo("b") //-1
"b".compareTo("a") //1
"a".compareTo("a") //0
```

こちらも、IgnoreCaseをつけると大文字・小文字を無視して比較可能。

```java
str.compareToIgnoreCase("String型文字列")
```

#### 検索

##### 真偽判定

指定文字列が含まれるか。
戻り値はboolean。

```java
str.contains("String型文字列")
```

正規表現を使う場合は、matchesメソッドを使う。

```java
str.matches("正規表現")
```

前方一致。
戻り値はboolean。

```java
str.startsWith("String型文字列")
```

後方一致。
戻り値はboolean。

```java
str.endsWith("String型文字列")
```

##### indexの取得
指定された部分文字列が最初に出現する位置のindexを返す。
引数を追加すると、それ以降で最初に出現する位置のindexを返す。
戻り値はint型。

```java
str.indexOf("String型文字列")
str.indexOf("String型文字列", int fromIndex)
```

同様に、最後に出現する位置のindexを返すLastindexOfというメソッドもある。

```java
str.lastIndexOf("String型文字列")
str.lastIndexOf("String型文字列", int fromIndex)
```

#### 文字列の置換
指定文字列が含まれる場合、それらを全て置き換える。
戻り値はString型。

```java
str.replace("指定文字列", "置換文字列")
```

また、replaceAllを使えば、正規表現が利用できる。

```java
str.replaceAll("指定文字列（正規表現可）", "置換文字列")
```

初めの指定文字列だけを置換したい場合は、replaceFirstを用いる。
replaceFirstも、replaceAllと同様に正規表現が使える。

```java
str.replaceFirst("指定文字列（正規表現可）", "置換文字列")
```

#### 大文字・小文字の変換
戻り値はString型。

```java
str.toUpperCase() //大文字に
str.toLowerCase() //小文字に
```

#### 文字列への変換
String.valueOf()で数値をはじめとする様々な型を文字列に変換することができる。
戻り値はString型。

```java
String.valueOf(int num)
```

char型配列を引数とするとその配列をつなぎ合わせた文字列となる。

```java
char[] c = {'a', 'b', 'c'};
String.valueOf(c) //"abc"が返される
```

数字の桁数を取得したい時などに便利である。

```java
int N = 100000;
String.valueOf(N).length() //6桁とわかる
```

###  StringBuilderの使い方まとめ

#### StringからStringBuilderへの変換
下記のように構築する。

```java
StringBuilder sb = new StringBuilder(str)
```

#### StringBuilderからStringへの変換
toStringでString型に変換できる。

```java
sb.toString()
```

#### 文字列の結合
appendがString型の+に相当する。
引数はString型でなく、int型やchar型などでも良い。

```java
sb.append("結合したいもの")
```

任意の場所に挿入したいときは、insertを用いる。

```java
sb.insert(int index, "結合したいもの")
```

#### 部分文字列の削除
indexを指定し、部分文字列を消去できる。
他のメソッド同様、endIndexは含まれない。

```java
sb.delete(int beginIndex, int endIndex)
```

#### 任意のindexの文字を変える
setCharAtで、任意のindexの文字を別の文字に置き換えることができる。

```java
sb.setCharAt(int index, char c)
//sb.setCharAt(1, 'z')とすれば、azcとなる
```

#### 文字列の反転
reverseで反転した文字列が得られる。

```java
sb.reverse()
```

#### 文字列の置換
indexを指定した部分文字列を、任意の文字列に変換する。

```java
sb.replace(int start, int end, "置換文字列")
```

#### String型と同じ操作

##### 長さの取得

```java
sb.length()
```

##### N文字目の取得

```java
sb.charAt(int index)
```

##### indexの取得

```java
sb.indexOf("String型文字列")
sb.indexOf("String型文字列", int fromIndex)
sb.lastIndexOf("String型文字列")
sb.lastIndexOf("String型文字列", int fromIndex)
```



### まとめ
String型とStringBuilderクラスの操作をまとめた。
普段はString型を使えば良いが、操作を何度も行い実行時間がかかる場合や、反転などの操作を行う際は、StringBuilderクラスを使うと良い。

また、競技プログラミングにおいて、何度も文字列を出力すると時間がかかるので、その場合はStringBuilderにappendしていき、最後に1回でまとめて出力すると良い。
改行が必要な場合は、"\n"をappendすれば良い。

### 参考
Oracle Help Center
[Stringクラスの説明](https://docs.oracle.com/javase/jp/8/docs/api/java/lang/String.html)
[StringBuilderクラスの説明](https://docs.oracle.com/javase/jp/8/docs/api/java/lang/StringBuilder.html)