concat()と append() の違い　Java(メモリを食うのか食わないのか)

## はじめに
インフラの分野でも、Iac化が進んで行くと考えています。そこで、ノウハウが体系だっているものが学び易いと考えて、Javaを学びはじめました。その際に、学んだことで、違いを理解しておく必要があると考えたものをまとめてみました。

使い方と動作の違い
--

### ざっくりとした理解
文字列を繰り返し結合する場合や、大量の結合を行う場合は、パフォーマンス向上のために `.append()` を使用する。

### 1. `.concat()` メソッド
- **クラス**: `String` クラス
- **目的**: 文字列を結合するためのメソッド。
- **使用例**:
  ```java
  String str1 = "Hello";
  String str2 = "World";
  String result = str1.concat(str2);
  System.out.println(result);  // 出力: "HelloWorld"
  ```
- **特徴**:
  - `String` は不変（immutable）なので、`concat()` メソッドは新しい文字列を生成して返す。
  - 文字列が結合されるだけで、元の文字列 `str1` や `str2` は変更されない。
  - `concat()` メソッドは引数として文字列を1つだけ取る。
  - パフォーマンスに関しては、`String` クラスの文字列を結合するためには新しい文字列オブジェクトを作成するため、頻繁に文字列結合を行う場合には効率が悪くなることがある。

### 2. `.append()` メソッド
- **クラス**: `StringBuilder` または `StringBuffer` クラス
- **目的**: 文字列の追加（結合）を効率的に行うためのメソッド。
- **使用例**:
  ```java
  StringBuilder sb = new StringBuilder("Hello");
  sb.append("World");
  System.out.println(sb.toString());  // 出力: "HelloWorld"
  ```
- **特徴**:
  - `StringBuilder` は可変（mutable）なクラスで、`append()` メソッドは元のオブジェクトに対して直接文字列を追加。
  - `StringBuilder` は文字列の結合を効率的に行うため、繰り返し行う場合でも新しいオブジェクトを作成せずに内部バッファを変更して処理します。そのため、`StringBuilder` や `StringBuffer` はパフォーマンスが良い。
  - `append()` メソッドは、文字列以外にもさまざまな型のオブジェクト（例えば `int` や `double` など）を引数として取ることができる。
  
  ```java
  StringBuilder sb = new StringBuilder("Hello");
  sb.append(123);  // 数字を追加
  System.out.println(sb.toString());  // 出力: "Hello123"
  ```

### 主な違い
| 特徴                       | `.concat()`                         | `.append()`                        |
|----------------------------|-------------------------------------|------------------------------------|
| クラス                     | `String`                            | `StringBuilder` または `StringBuffer` |
| 可変性                     | 不変（immutable）                   | 可変（mutable）                    |
| パフォーマンス              | 頻繁な結合には効率が悪い             | 繰り返しの結合に最適、効率的       |
| 使用するクラス              | `String` のインスタンスでのみ使用  | `StringBuilder` または `StringBuffer` で使用 |
| 引数の型                    | `String` だけ                       | 他の型（例: `int`, `char`, `boolean` など）も受け取る |
| 結果                        | 新しい `String` インスタンスを返す | `StringBuilder` インスタンスが変更される |

`String` と `StringBuilder` の違い
--

違いは主に**可変性（mutable）** と **不変性（immutable）** に関するもの。

### 1. `String` クラス
- **不変（immutable）**: `String` クラスのインスタンスは一度作成されると変更できない。文字列の操作（結合、置換、削除など）を行うと、新しい`String` オブジェクトが作成される。
- **例**:
  ```java
  String str = "Hello";
  str = str + " World";  // 新しい String オブジェクトが作成される
  ```
`str` の元の値 `"Hello"` は変更されず、新しい文字列 `"Hello World"` が作成される。

- **注意点**:
  - 文字列が頻繁に変更される場合（例えば繰り返し結合する場合）にパフォーマンスが低下することがある。なぜなら、新しい `String` オブジェクトを毎回作成し、そのたびにメモリを再割り当てする必要があるから。

### 2. `StringBuilder` クラス
- **可変（mutable）**: `StringBuilder` のインスタンスは、作成後に内容を変更できる。新しいオブジェクトを作成するのではなく、内部の文字列バッファを直接変更。
- **例**:
  ```java
  StringBuilder sb = new StringBuilder("Hello");
  sb.append(" World");  // 同じ StringBuilder インスタンスが変更される
  System.out.println(sb.toString());  // 出力: "Hello World"
  ```

- **注意点**:
  - 内部バッファを変更するため、メモリの再割り当てを避けることができる。

### 主な違い

| 特徴                | `String`                                     | `StringBuilder`                              |
|---------------------|----------------------------------------------|---------------------------------------------|
| **可変性**          | 不変（immutable）                           | 可変（mutable）                             |
| **文字列操作後の振る舞い** | 新しい `String` オブジェクトを作成            | 同じインスタンス内で変更が行われる         |
| **パフォーマンス**  | 頻繁な変更でパフォーマンスが低下する         | 変更が頻繁でも高パフォーマンス             |
| **メモリ使用**      | 各変更で新しいオブジェクトを生成するため、メモリを多く消費する場合がある | 内部バッファを使うため、メモリの再割り当てが少なく効率的 |
| **使用シーン**      | 変更しない文字列、または少量の文字列操作      | 文字列の繰り返し変更・結合、大量の文字列操作 |

concat()
--
```java
public class Sample {
    public static void main(String[] args) {
        // 正しい文字列リテラルを使用し、concatを使って文字列を結合
        String str = "hello".concat(", java!");
        System.out.println(str);  // 出力: hello, java!
    }
}
```

append() 
--
```java
public class Sample {
    public static void main(String[] args) {
        // StringBuilderを使用して文字列を結合
        StringBuilder sb = new StringBuilder();
        sb.append("hello");
        sb.append(", java!");
        
        // StringBuilderの内容を文字列として出力
        System.out.println(sb.toString());  // 出力: hello, java!
    }
}
```

まとめ
--
毎回、メモリを食う操作をするのか、しないのか、インフラに影響を与える箇所について、理解することができた。