Java文字列操作 チートシート

cheatsheet

1. 文字列の生成と基本操作 🛠️

文字列オブジェクトを作成し、基本的な情報を取得する方法です。

メソッド/操作 説明 コード例
リテラル ダブルクォートで囲んで文字列を直接生成します。最も一般的な方法です。
String str = "こんにちは";
new String() コンストラクタを使用して文字列オブジェクトを明示的に生成します。通常はリテラルで十分です。
char[] data = {'a', 'b', 'c'};
String str = new String(data); // "abc"
length() 文字列の長さ(文字数)を取得します。
String s = "Java";
int len = s.length(); // 4
charAt(int index) 指定されたインデックス(位置、0から始まる)にある文字 (char) を取得します。
String s = "World";
char c = s.charAt(1); // 'o'
codePointAt(int index) 指定されたインデックスにある文字のUnicodeコードポイント(整数値)を取得します。サロゲートペア(補助文字)に対応しています。
String emoji = "😊"; // サロゲートペアを含む文字列
int codePoint = emoji.codePointAt(0); // 128522 (絵文字のコードポイント)
int len = emoji.length(); // 2 (char単位では2文字)
int codePointCount = emoji.codePointCount(0, emoji.length()); // 1 (コードポイント単位では1文字)
toCharArray() 文字列を文字 (char) の配列に変換します。
String s = "Test";
char[] chars = s.toCharArray();
// chars は ['T', 'e', 's', 't']

関連ドキュメント: java.lang.String (Java SE 17)

2. 文字列の連結 ✨

複数の文字列や値を結合して新しい文字列を作成します。

メソッド/操作 説明 コード例 備考
+ 演算子 最も簡単な連結方法。内部的にはStringBuilder(またはStringBuffer)に変換されることがあります。
String s1 = "Hello";
String s2 = " World";
String result = s1 + s2 + "!"; // "Hello World!"
単純な連結には便利ですが、ループ内で大量に連結するとパフォーマンスが低下する可能性があります。
concat(String str) 文字列の末尾に指定した文字列を連結した新しい文字列を返します。
String s1 = "Java";
String s2 = " Programming";
String result = s1.concat(s2); // "Java Programming"
+演算子より若干明示的ですが、nullを連結しようとするとNullPointerExceptionが発生します。+演算子は”null”という文字列に変換します。
StringBuilder 変更可能な文字列を扱うクラス。多数の文字列を効率的に連結する場合に使用します。
StringBuilder sb = new StringBuilder();
sb.append("Apple");
sb.append(", ");
sb.append("Banana");
sb.append(", ");
sb.append("Cherry");
String result = sb.toString(); // "Apple, Banana, Cherry"
スレッドセーフではありませんが、StringBufferより高速です。通常はこちらを使用します。
StringBuilder Doc
StringBuffer StringBuilderと同様に変更可能な文字列を扱いますが、スレッドセーフです。
StringBuffer sbuf = new StringBuffer();
sbuf.append("Thread");
sbuf.append("-Safe");
String result = sbuf.toString(); // "Thread-Safe"
マルチスレッド環境で共有される文字列バッファが必要な場合に使用します。パフォーマンスはStringBuilderより劣ります。
StringBuffer Doc
String.join(CharSequence delimiter, CharSequence... elements) (Java 8+) 指定された区切り文字で複数の文字列要素を連結します。
String[] fruits = {"Apple", "Banana", "Cherry"};
String result = String.join(", ", fruits); // "Apple, Banana, Cherry"

List<String> list = List.of("One", "Two", "Three");
String result2 = String.join("-", list); // "One-Two-Three"
コレクションや配列の要素を簡単に連結できます。
StringJoiner (Java 8+) 区切り文字、接頭辞、接尾辞を指定して文字列を連結できます。
StringJoiner sj = new StringJoiner(", ", "[", "]");
sj.add("Red").add("Green").add("Blue");
String result = sj.toString(); // "[Red, Green, Blue]"
String.joinより柔軟な連結が可能です。
StringJoiner Doc

3. 文字列の比較 ⚖️

文字列の内容が等しいか、辞書順でどちらが先かを比較します。

メソッド 説明 コード例 備考
equals(Object anObject) 文字列の内容が完全に(大文字・小文字を区別して)等しいかどうかを比較します。
String s1 = "test";
String s2 = "test";
String s3 = "Test";
boolean b1 = s1.equals(s2); // true
boolean b2 = s1.equals(s3); // false
文字列の内容比較には==ではなくequals()を使用します。==はオブジェクト参照(メモリ上のアドレス)が同じかどうかを比較します(ただし、文字列リテラルの場合は同じ参照を指すことが多い)。
equalsIgnoreCase(String anotherString) 大文字・小文字を区別せずに文字列の内容が等しいかどうかを比較します。
String s1 = "test";
String s3 = "Test";
boolean b3 = s1.equalsIgnoreCase(s3); // true
ユーザー入力の比較などで有用です。
compareTo(String anotherString) 文字列を辞書順で比較します(大文字・小文字を区別)。
String s1 = "apple";
String s2 = "banana";
String s3 = "Apple";
int res1 = s1.compareTo(s2); // 負の値 (apple < banana)
int res2 = s1.compareTo(s1); // 0 (apple == apple)
int res3 = s1.compareTo(s3); // 正の値 (apple > Apple, 小文字 > 大文字)
戻り値: 自身が引数より小さい場合は負の値、等しい場合は0、大きい場合は正の値。ソートなどで使用されます。
compareToIgnoreCase(String str) 大文字・小文字を区別せずに文字列を辞書順で比較します。
String s1 = "apple";
String s3 = "Apple";
int res4 = s1.compareToIgnoreCase(s3); // 0 (apple == Apple, ケース無視)
大文字・小文字を区別しないソートなどで使用されます。

4. 文字列の検索と部分取得 🔍

文字列内に特定の文字や部分文字列が含まれているか検索したり、一部分を切り出したりします。

メソッド 説明 コード例
indexOf(int ch) / indexOf(String str) 指定された文字/文字列が最初に出現するインデックスを返します。見つからない場合は -1 を返します。
String s = "abracadabra";
int idx1 = s.indexOf('a');     // 0
int idx2 = s.indexOf("bra");   // 1
int idx3 = s.indexOf('z');     // -1
indexOf(int ch, int fromIndex) / indexOf(String str, int fromIndex) 指定されたインデックス以降で、指定された文字/文字列が最初に出現するインデックスを返します。
String s = "abracadabra";
int idx4 = s.indexOf('a', 1);  // 3 (インデックス1以降で探す)
int idx5 = s.indexOf("bra", 2); // 8
lastIndexOf(int ch) / lastIndexOf(String str) 指定された文字/文字列が最後に出現するインデックスを返します。見つからない場合は -1 を返します。
String s = "abracadabra";
int idx6 = s.lastIndexOf('a');     // 10
int idx7 = s.lastIndexOf("bra");   // 8
lastIndexOf(int ch, int fromIndex) / lastIndexOf(String str, int fromIndex) 指定されたインデックス以前で、指定された文字/文字列が最後に出現するインデックスを返します(逆方向に検索)。
String s = "abracadabra";
int idx8 = s.lastIndexOf('a', 9);  // 7 (インデックス9以前で探す)
int idx9 = s.lastIndexOf("bra", 7); // 1
contains(CharSequence s) 指定された文字列(シーケンス)がこの文字列に含まれているかどうかを返します (boolean)。
String s = "Hello World";
boolean b1 = s.contains("World"); // true
boolean b2 = s.contains("world"); // false (大文字小文字区別)
startsWith(String prefix) この文字列が指定された接頭辞で始まるかどうかを返します (boolean)。
String s = "filename.txt";
boolean b1 = s.startsWith("file"); // true
boolean b2 = s.startsWith("name", 4); // true (インデックス4から始まる部分が"name"か)
endsWith(String suffix) この文字列が指定された接尾辞で終わるかどうかを返します (boolean)。
String s = "filename.txt";
boolean b1 = s.endsWith(".txt"); // true
boolean b2 = s.endsWith("TXT"); // false
substring(int beginIndex) 指定された開始インデックスから文字列の末尾までの部分文字列を返します。
String s = "Programming";
String sub1 = s.substring(3); // "gramming"
substring(int beginIndex, int endIndex) 指定された開始インデックスから終了インデックスの手前まで(終了インデックスの文字は含まない)の部分文字列を返します。
String s = "Programming";
String sub2 = s.substring(3, 7); // "gram" (インデックス3から6まで)

5. 文字列の置換 🔄

文字列内の一部を別の文字や文字列で置き換えます。

メソッド 説明 コード例 備考
replace(char oldChar, char newChar) 文字列内に出現するすべてのoldCharnewCharに置換した新しい文字列を返します。
String s = "mississippi";
String replaced = s.replace('i', '!'); // "m!ss!ss!pp!"
文字単位の置換です。
replace(CharSequence target, CharSequence replacement) 文字列内に出現するすべてのtarget(文字列シーケンス)をreplacementに置換した新しい文字列を返します。
String s = "catdogcat";
String replaced = s.replace("cat", "fish"); // "fishdogfish"
文字列単位の置換です。正規表現は解釈しません。
replaceAll(String regex, String replacement) 指定された正規表現 (regex) に一致するすべての部分をreplacement文字列に置換した新しい文字列を返します。
String s = "abc123def456";
String replaced = s.replaceAll("\\d+", "#"); // "abc#def#" (数字の連続を#に置換)
正規表現を使用するため、複雑なパターンでの置換が可能です。replacement内では$1, $2などでキャプチャグループを参照できます。
replaceFirst(String regex, String replacement) 指定された正規表現 (regex) に最初に一致した部分のみをreplacement文字列に置換した新しい文字列を返します。
String s = "abc123def123";
String replaced = s.replaceFirst("\\d+", "#"); // "abc#def123" (最初の数字連続のみ置換)
正規表現に一致する最初の箇所だけ置換したい場合に使用します。

6. 文字列の分割と結合 🔗

特定の区切り文字で文字列を分割したり、複数の文字列を結合したりします。

メソッド 説明 コード例 備考
split(String regex) 指定された正規表現 (regex) に一致する箇所で文字列を分割し、文字列配列 (String[]) として返します。
String s = "apple,banana,cherry";
String[] parts = s.split(","); // ["apple", "banana", "cherry"]

String s2 = "one; two three\tfour";
String[] parts2 = s2.split("\\s*[;,\\s]\\s*"); // ["one", "two", "three", "four"] (空白、カンマ、セミコロンで分割)
区切り文字自体は結果に含まれません。末尾の空文字列はデフォルトでは除去されます。特殊文字(., |, *など)を区切り文字にする場合はエスケープが必要です (例: split("\\."))。
split(String regex, int limit) 分割の挙動をlimitパラメータで制御します。
  • limit > 0: 最大 limit 個の要素に分割(最後の要素は残りの部分すべて)。
  • limit == 0: split(regex)と同じ。末尾の空文字列は除去。
  • limit < 0: すべての部分に分割。末尾の空文字列も保持。
String s = "a,b,c,,";
String[] parts1 = s.split(",");       // ["a", "b", "c"] (limit=0相当)
String[] parts2 = s.split(",", 5);    // ["a", "b", "c", "", ""] (limit > 0)
String[] parts3 = s.split(",", -1);   // ["a", "b", "c", "", ""] (limit < 0)

String s2 = "a:b:c";
String[] parts4 = s2.split(":", 2); // ["a", "b:c"] (最大2要素)
分割数を制限したり、末尾の空要素の扱いを制御したい場合に使用します。
String.join(CharSequence delimiter, CharSequence... elements) (Java 8+) 指定された区切り文字で複数の文字列要素(可変長引数または配列)を連結します。
String[] arr = {"Java", "Python", "Ruby"};
String joined = String.join(" | ", arr); // "Java | Python | Ruby"
配列や可変長引数を連結する際に便利です。(「2. 文字列の連結」も参照)
String.join(CharSequence delimiter, Iterable elements) (Java 8+) 指定された区切り文字で Iterable (List, Set など) の要素を連結します。
List<String> list = List.of("Spring", "Hibernate", "JPA");
String joined = String.join(", ", list); // "Spring, Hibernate, JPA"
コレクションの要素を連結する際に便利です。
StringJoiner (Java 8+) 区切り文字、接頭辞、接尾辞を指定して柔軟に文字列を連結します。
StringJoiner sj = new StringJoiner("/", "prefix-", "-suffix");
sj.add("path1").add("path2");
String result = sj.toString(); // "prefix-path1/path2-suffix"
より複雑なフォーマットでの結合が必要な場合。(「2. 文字列の連結」も参照)

7. 大文字・小文字変換と空白除去 🧹

文字列全体のケース(大文字・小文字)を変換したり、先頭や末尾の空白文字を除去したりします。

メソッド 説明 コード例 備考
toLowerCase() 文字列内のすべての大文字を小文字に変換した新しい文字列を返します。デフォルトロケールに基づきます。
String s = "Hello World";
String lower = s.toLowerCase(); // "hello world"
特定のロケール(言語・地域)を考慮する場合は toLowerCase(Locale locale) を使用します。
toUpperCase() 文字列内のすべての小文字を大文字に変換した新しい文字列を返します。デフォルトロケールに基づきます。
String s = "Hello World";
String upper = s.toUpperCase(); // "HELLO WORLD"
特定のロケールを考慮する場合は toUpperCase(Locale locale) を使用します。
trim() 文字列の先頭と末尾にある空白文字(Unicode値が U+0020 以下)を除去した新しい文字列を返します。
String s = "   Spaces Everywhere!   \t\n";
String trimmed = s.trim(); // "Spaces Everywhere!"
全角スペースや改行コードなど、一部の空白文字は除去されません。
strip() (Java 11+) 文字列の先頭と末尾にあるすべての空白文字(Character.isWhitespace() が true を返す文字)を除去した新しい文字列を返します。
String s = "   \u2005Spaces Everywhere!\u3000   \t\n"; // 全角スペースや他の空白文字を含む
String stripped = s.strip(); // "Spaces Everywhere!"
trim() よりも多くの種類の空白文字(全角スペースなど)に対応しています。Java 11以降で利用可能です。
stripLeading() (Java 11+) 文字列の先頭にあるすべての空白文字(Character.isWhitespace() が true を返す文字)を除去した新しい文字列を返します。
String s = "   Leading Spaces   ";
String stripped = s.stripLeading(); // "Leading Spaces   "
Java 11以降で利用可能です。
stripTrailing() (Java 11+) 文字列の末尾にあるすべての空白文字(Character.isWhitespace() が true を返す文字)を除去した新しい文字列を返します。
String s = "   Trailing Spaces   ";
String stripped = s.stripTrailing(); // "   Trailing Spaces"
Java 11以降で利用可能です。

8. 書式設定とフォーマット 📝

指定された書式文字列に従って、数値や日付などを埋め込んだ文字列を生成します。

メソッド 説明 コード例 備考
static String format(String format, Object... args) 指定された書式文字列 (format) と引数 (args) を使用して、フォーマットされた文字列を返します。
String name = "Alice";
int age = 30;
double height = 1.65;
String message = String.format("名前: %s, 年齢: %d歳, 身長: %.2f m", name, age, height);
// message: "名前: Alice, 年齢: 30歳, 身長: 1.65 m"

// %s: 文字列, %d: 整数, %f: 浮動小数点数, %.2f: 小数点以下2桁
// %t: 日時 (例: %tF - YYYY-MM-DD)
java.util.Date now = new java.util.Date();
String dateStr = String.format("今日の日付: %tF", now);
C言語のprintfスタイルの書式指定子を使用します。数値の桁数、ゼロ埋め、日付/時刻フォーマットなど、多様な指定が可能です。
書式指定子の詳細は Formatter Syntax を参照。
System.out.printf(String format, Object... args) String.formatと同様の書式で、結果を標準出力(コンソール)に直接出力します。
String item = "Laptop";
int price = 120000;
System.out.printf("商品: %s, 価格: %,d円%n", item, price);
// 出力: 商品: Laptop, 価格: 120,000円 (改行付き)
デバッグ出力などで便利です。%n はプラットフォーム依存の改行文字を出力します。
java.text.MessageFormat 位置に基づいたフォーマット(例: {0}, {1})を提供します。国際化対応(i18n)でよく使われます。
import java.text.MessageFormat;

String pattern = "ファイル ''{0}'' が見つかりません。エラーコード: {1,number,integer}";
String message = MessageFormat.format(pattern, "config.xml", 404);
// message: "ファイル 'config.xml' が見つかりません。エラーコード: 404"
引数の順序を入れ替えたり、数値や日付のフォーマットを細かく指定できます。
MessageFormat Doc

9. 空・ブランク判定 ✅

文字列が空(長さ0)であるか、または空白文字のみで構成されているかを判定します。

メソッド 説明 コード例 備考
isEmpty() 文字列の長さが 0 である場合にのみ true を返します。
String s1 = "";
String s2 = " ";
String s3 = "abc";

boolean b1 = s1.isEmpty(); // true
boolean b2 = s2.isEmpty(); // false (空白文字があるので長さは1)
boolean b3 = s3.isEmpty(); // false
nullチェックは別途必要です (str != null && str.isEmpty())。
isBlank() (Java 11+) 文字列が空であるか、または空白文字(Character.isWhitespace() が true を返す文字)のみで構成されている場合に true を返します。
String s1 = "";
String s2 = "   "; // 半角スペースのみ
String s3 = "\t\n"; // タブと改行のみ
String s4 = " abc ";
String s5 = "\u3000"; // 全角スペースのみ

boolean b1 = s1.isBlank(); // true
boolean b2 = s2.isBlank(); // true
boolean b3 = s3.isBlank(); // true
boolean b4 = s4.isBlank(); // false
boolean b5 = s5.isBlank(); // true
isEmpty()よりも実用的で、ユーザー入力のバリデーションなどに便利です。nullチェックは別途必要です。Java 11以降で利用可能です。
注意: isEmpty()isBlank() を呼び出す前に、対象の文字列変数が null でないことを確認してください。null に対してこれらのメソッドを呼び出すと NullPointerException が発生します。
安全なチェック方法: str == null || str.isBlank()

10. 正規表現の利用 🧩

正規表現パターンを用いて、文字列の検索、置換、検証などを高度に行います。

クラス/メソッド 説明 コード例 備考
String#matches(String regex) 文字列全体が指定された正規表現 (regex) に完全に一致するかどうかを判定します (boolean)。
String email = "test@example.com";
String regex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
boolean isValid = email.matches(regex); // true

String phone = "090-1234-5678";
boolean isPhone = phone.matches("\\d{3}-\\d{4}-\\d{4}"); // true
簡単なバリデーションに適しています。内部的にはPattern.matches(regex, this)を呼び出します。
java.util.regex.Pattern 正規表現パターンを表すクラス。パターンをコンパイルして効率的なマッチングを実現します。
import java.util.regex.Pattern;

String regex = "\\bJava\\b"; // 単語としての "Java"
Pattern pattern = Pattern.compile(regex); // パターンをコンパイル

// Pattern.compile(regex, Pattern.CASE_INSENSITIVE); // 大文字小文字無視
同じ正規表現を繰り返し使用する場合、事前にコンパイルしておくとパフォーマンスが向上します。
Pattern Doc
java.util.regex.Matcher Patternオブジェクトと入力文字列に対してマッチング操作を行うためのエンジン。
import java.util.regex.Matcher;
import java.util.regex.Pattern;

String text = "Java is fun, Java is powerful.";
Pattern pattern = Pattern.compile("Java");
Matcher matcher = pattern.matcher(text); // Matcher を作成

// find(): 次に一致する箇所を検索
while (matcher.find()) {
    System.out.printf("Found '%s' at index %d to %d%n",
        matcher.group(), matcher.start(), matcher.end());
}
// 出力:
// Found 'Java' at index 0 to 4
// Found 'Java' at index 13 to 17

// lookingAt(): 文字列の先頭から一致するかどうか
boolean startsWithJava = matcher.lookingAt(); // true

// matches(): 文字列全体が一致するかどうか (String#matches と同様)
Matcher fullMatcher = Pattern.compile(".*powerful\\.").matcher(text);
boolean fullMatch = fullMatcher.matches(); // true
find(), group(), start(), end(), lookingAt(), matches(), replaceAll(), replaceFirst() などのメソッドを提供します。
Matcher Doc
Matcher#group(int group) 正規表現中のキャプチャグループ(括弧 () で囲まれた部分)に一致した部分文字列を取得します。group(0) はマッチ全体を返します。
// 例: 日付 "YYYY-MM-DD" から年、月、日を抽出
String date = "2023-10-26";
Pattern datePattern = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher dateMatcher = datePattern.matcher(date);

if (dateMatcher.matches()) {
    String year = dateMatcher.group(1);  // "2023" (最初のグループ)
    String month = dateMatcher.group(2); // "10"   (2番目のグループ)
    String day = dateMatcher.group(3);   // "26"   (3番目のグループ)
    System.out.printf("Year: %s, Month: %s, Day: %s%n", year, month, day);
}
複雑な文字列から特定の情報を抽出する際に非常に強力です。
正規表現の注意点:
  • バックスラッシュ \ はJavaの文字列リテラル内と正規表現の両方で特殊文字であるため、正規表現内でバックスラッシュ自体を表すには \\\\ (例: \d -> "\\d", \ -> "\\\\") とエスケープする必要があります。
  • 複雑な正規表現や巨大な入力文字列に対するマッチングは、パフォーマンスに影響を与える可能性があります(ReDoS攻撃のリスク)。

11. その他の便利なメソッド ✨

Javaのバージョンアップ等で追加された、特定の状況で便利なメソッドです。

メソッド 説明 コード例 備考
repeat(int count) (Java 11+) 文字列を指定された回数 (count) 繰り返した新しい文字列を返します。
String s = "abc";
String repeated = s.repeat(3); // "abcabcabc"

String line = "-".repeat(10); // "----------"
countが0の場合は空文字列を返します。負の場合はIllegalArgumentExceptionが発生します。Java 11以降で利用可能です。
lines() (Java 11+) 文字列を行終端文字 (\n, \r, \r\n) で分割し、各行を要素とする Stream<String> を返します。
String multiLine = "Line 1\nLine 2\r\nLine 3";
multiLine.lines()
    .map(line -> ">> " + line)
    .forEach(System.out::println);
// 出力:
// >> Line 1
// >> Line 2
// >> Line 3
Stream API と組み合わせて、複数行のテキスト処理を簡潔に記述できます。Java 11以降で利用可能です。
indent(int n) (Java 12+) 文字列の各行の先頭に指定された数 (n) のスペースを追加(インデント)します。nが負の場合は、可能なら先頭の空白を削除します。
String text = "{\n  \"key\": \"value\"\n}";
String indented = text.indent(2);
/*
出力:
  {
    "key": "value"
  }
*/

String html = "  
\n

Text

\n
"; String deIndented = html.indent(-2); /* 出力:

Text

*/ System.out.println(indented); System.out.println(deIndented);
コード整形やテキストブロックの操作に便利です。Java 12以降で利用可能です。
transform(Function f) (Java 12+) 文字列自身を引数として受け取る関数 (Function) を適用し、その結果を返します。メソッドチェーン内で任意の処理を挟むのに便利です。
import java.util.function.Function;

String data = "  123,456  ";

// 例: トリミングしてIntegerに変換
Integer number = data.transform(String::strip)
                      .transform(s -> s.replace(",", ""))
                      .transform(Integer::parseInt); // number = 123456

// 例: 複雑な処理を挟む
String result = "input"
    .transform(s -> s + ":processed")
    .transform(String::toUpperCase); // result = "INPUT:PROCESSED"

System.out.println(number);
System.out.println(result);
ラムダ式やメソッド参照と組み合わせて使います。Java 12以降で利用可能です。
intern() 文字列が文字列プールに存在すればその参照を返し、存在しなければプールに追加してその参照を返します。
String s1 = new String("hello"); // ヒープ上に新しいオブジェクト
String s2 = "hello";             // プール内のリテラル
String s3 = s1.intern();         // プール内の "hello" の参照を取得

System.out.println(s1 == s2); // false (異なるオブジェクト)
System.out.println(s2 == s3); // true (プール内の同じオブジェクトを指す)
大量の重複する文字列が存在する場合にメモリ使用量を削減できる可能性がありますが、パフォーマンスへの影響(プールの検索コスト)も考慮する必要があります。通常は明示的に使用する必要性は低いです。

12. 文字列とバイト配列の変換 ⚙️

文字列を指定された文字エンコーディングでバイト配列に変換したり、バイト配列を文字列に変換したりします。

メソッド/コンストラクタ 説明 コード例 備考
getBytes() プラットフォームのデフォルト文字セットを使用して、文字列をバイト配列にエンコードします。
String s = "こんにちは";
byte[] bytes = s.getBytes(); // デフォルトエンコーディング (例: UTF-8, MS932)
プラットフォーム依存のため、意図しないエンコーディングになる可能性があります。非推奨です。
getBytes(String charsetName) / getBytes(Charset charset) 指定された文字セット(エンコーディング、例: “UTF-8”, StandardCharsets.UTF_8)を使用して、文字列をバイト配列にエンコードします。
import java.nio.charset.StandardCharsets;
import java.io.UnsupportedEncodingException;

String s = "こんにちは";
try {
    byte[] utf8Bytes = s.getBytes("UTF-8");
    byte[] sjisBytes = s.getBytes("Shift_JIS"); // MS932などプラットフォームによる
    // Java 7+ 推奨
    byte[] utf8Bytes_v2 = s.getBytes(StandardCharsets.UTF_8);
} catch (UnsupportedEncodingException e) {
    // 指定された文字セットがサポートされていない場合
    e.printStackTrace();
}
ファイルI/Oやネットワーク通信など、エンコーディングが重要な場面では、必ず文字セットを明示的に指定してください。StandardCharsets (Java 7+) の使用が推奨されます。
new String(byte[] bytes) プラットフォームのデフォルト文字セットを使用して、バイト配列をデコードして新しい文字列を構築します。
// bytes がデフォルトエンコーディングでエンコードされている前提
// String decoded = new String(bytes);
getBytes() 同様、プラットフォーム依存のため非推奨です。
new String(byte[] bytes, String charsetName) / new String(byte[] bytes, Charset charset) 指定された文字セットを使用して、バイト配列をデコードして新しい文字列を構築します。
import java.nio.charset.StandardCharsets;
import java.io.UnsupportedEncodingException;

// utf8Bytes が UTF-8 でエンコードされている前提
byte[] utf8Bytes = ... ; // 事前に取得したバイト配列
try {
    String decodedUtf8 = new String(utf8Bytes, "UTF-8");
    // Java 7+ 推奨
    String decodedUtf8_v2 = new String(utf8Bytes, StandardCharsets.UTF_8);
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}
バイト配列の元のエンコーディングを正しく指定することが重要です。間違った文字セットを指定すると文字化けが発生します。StandardCharsets (Java 7+) の使用が推奨されます。
エンコーディングの重要性: 文字列とバイト配列の相互変換では、常に文字エンコーディング(UTF-8, Shift_JIS, EUC-JPなど)を意識し、明示的に指定することが文字化けを防ぐ鍵となります。特に指定がない場合、JVMやOSのデフォルト設定に依存し、環境によって挙動が変わる可能性があります。UTF-8 が現在最も広く使われている推奨エンコーディングです。

13. パフォーマンスに関する考慮事項 🤔

文字列操作、特に連結はパフォーマンスに影響を与えることがあります。

  • 文字列連結:
    • 単純な連結(2~3個程度)であれば + 演算子で問題ありません。近年のJVMでは多くの場合 StringBuilder を使ったコードにコンパイル(最適化)されます。
    • ループ内での文字列連結には + 演算子を使うべきではありません。ループの各イテレーションで新しい String オブジェクトと内部的な StringBuilder オブジェクトが生成される可能性があり、非効率です。
    • ループ内で文字列を連結する場合は、明示的に StringBuilder (シングルスレッド環境) または StringBuffer (マルチスレッド環境) を使用してください。事前に適切な初期容量を指定すると、さらに効率が向上することがあります (new StringBuilder(estimatedCapacity))。
    // 非推奨: ループ内での + 演算子
    String resultBad = "";
    for (int i = 0; i < 1000; i++) {
        resultBad += " " + i; // 毎回新しいStringとStringBuilderが生成される可能性
    }
    
    // 推奨: StringBuilder を使用
    StringBuilder sbGood = new StringBuilder();
    for (int i = 0; i < 1000; i++) {
        sbGood.append(" ").append(i); // 効率的な追加
    }
    String resultGood = sbGood.toString();
  • 不変性 (Immutability): String オブジェクトは不変です。replace(), substring(), toLowerCase() などのメソッドは、元の文字列を変更するのではなく、新しい String オブジェクトを生成して返します。変更が頻繁に必要な場合は、StringBuilderStringBuffer の使用を検討してください。
  • 正規表現: 正規表現は強力ですが、コンパイルやマッチングにコストがかかります。同じ正規表現パターンを繰り返し使用する場合は、Pattern.compile() で事前にコンパイルしておくことでパフォーマンスを改善できます。複雑すぎる正規表現は処理に時間がかかる(場合によっては指数関数的に増大する)可能性があるため注意が必要です。
  • intern() メソッド: 文字列プールの利用はメモリ削減に繋がる場合がありますが、プールの検索や管理にはコストがかかります。プロファイリングを行わずに多用することは推奨されません。

コメント

タイトルとURLをコピーしました