JavaのisEmptyとisBlankでnull・空文字・空白を判定する違いを解説する記事のアイキャッチ。

実装・エラー解決

JavaのisEmptyとisBlankの違い|null・空文字・空白の判定方法

AIによる要約

isEmptyは文字数が0かを判定し、空白だけの文字列はfalseです。isBlankは空文字または空白文字だけならtrueになります。どちらも呼び出し元がnullならNullPointerExceptionです。画面入力では未送信、空文字、空白だけ、値ありを区別し、必須項目ならisBlank、空文字だけを特別扱いするならisEmptyなど、業務仕様に合わせます。trimとstripは文字列を変換するメソッドで、判定とは役割が異なります。

新人SE
新人SE
入力欄にスペースだけ入れたのに、isEmptyがfalseでした。
ポンコツSE
ポンコツSE
isEmptyは文字数だけを見ます。空白だけも未入力としたいならisBlankを検討します。

入力チェックでは『値がない』という言葉をよく使いますが、Java上ではnull、空文字、半角スペース、全角スペース、タブ、改行が別の状態です。これらを同じとみなすかは項目ごとに異なります。

必須チェックへisEmptyだけを使うと、スペースだけの氏名や備考が通過します。一方、パスワードや固定長コードでは空白も有効文字かもしれません。APIの違いを理解し、入力仕様を先に決めます。

この記事のポイント

  • isEmptyはlengthが0かを判定する
  • isBlankは空文字または空白文字だけならtrue
  • nullへ呼ぶとどちらもNullPointerException
  • trimとstripは変換であり判定ではない
  • 空白を未入力扱いするかは項目仕様で決める

null・空文字・空白の判定結果を比較する

空文字だけならisEmpty、空白だけも未入力扱いにするならisBlankを選びます。Java 11以降のAPIで、次の結果はJava 17で確認しました。nullの行の「例外」はNullPointerExceptionです。

入力値value.isEmpty()value.isBlank()value == null || value.isBlank()
null例外例外true
空文字 ""truetruetrue
半角空白 " "falsetruetrue
全角空白 " "(U+3000)falsetruetrue
タブ "\t"falsetruetrue
改行 "\n"falsetruetrue
文字あり " A "falsefalsefalse
改行しない空白 "\u00A0"(NBSP)falsefalsefalse

isBlankの空白判定はCharacter.isWhitespaceに基づきます。見た目が空白でもNBSPは対象外です。外部ファイルやコピーした文字列を受け取る場合は、業務仕様に必要な文字もテストしてください。 8行の結果をJava 17で表示する

isEmptyは文字数0だけを判定する

isEmpty()はlength() == 0と同じ意味です。半角スペースが1文字あれば空ではないためfalseになります。

System.out.println("".isEmpty());   // true
System.out.println(" ".isEmpty());  // false
System.out.println(" ".isEmpty()); // false
System.out.println("A".isEmpty());  // false

空白を有効な値として残す処理や、区切り後に空文字だけを検出する処理ではisEmptyが意図に合う場合があります。必須入力へ機械的に使うとは限りません。

isBlankは空白だけもtrue

Java 11以降のisBlank()は、空文字またはすべての文字が空白文字ならtrueです。半角スペース、タブ、改行などを空白として扱います。

System.out.println("".isBlank());    // true
System.out.println("   ".isBlank()); // true
System.out.println("\t".isBlank());  // true
System.out.println("A ".isBlank());  // false

空白の定義は単純な半角スペースだけではありません。古いJavaや独自ユーティリティを使う案件では、どのUnicode文字を空白として扱うか既存仕様を確認します。

nullにはどちらも使えない

nullはStringオブジェクトが存在しない状態なので、インスタンスメソッドを呼べません。nullの可能性がある入力では先に判定します。

static boolean isMissing(String value) {
    return value == null || value.isBlank();
}

同じ判定が何度も出るなら、Bean Validationの@NotBlank、案件標準のStringユーティリティ、Formの正規化など、境界で統一します。ただし独自メソッド名は『何を未入力とするか』が分かる名前にします。

trim・stripとの違い

trimとstripはそれぞれの基準に従って前後の文字を取り除いた結果を返します。isBlankは値を変えず判定します。LocalDateと同様、Stringも不変なので戻り値を使う必要があります。

String input = "  ABC  ";
input.strip();
System.out.println(input); // 空白は残る

String normalized = input.strip();
System.out.println(normalized); // ABC

入力を勝手にtrimすると、パスワードや固定桁コード、備考の意図した空白を壊す可能性があります。正規化する項目と、入力をそのまま保持する項目を分けます。

trim()は文字コードがU+0020以下の文字を前後から除去し、strip()はCharacter.isWhitespaceに基づきます。たとえば全角空白だけの文字列はtrim().isEmpty()がfalse、strip().isEmpty()がtrueになります。NBSPはどちらでも除去されません。

Formの必須チェックでは@NotBlankを検討する

Spring MVCのFormでは、Controller内でifを重ねるよりBean Validationで宣言できます。@NotNull、@NotEmpty、@NotBlankは許可する状態が異なります。

class UserForm {
    @NotBlank(message = "氏名を入力してください")
    private String name;

    @NotEmpty(message = "権限を1つ以上選択してください")
    private List<String> roles;
}

文字列の必須入力にはNotBlankがよく合いますが、すべての項目へ同じアノテーションを付けません。数値、List、チェックボックス、任意項目の仕様に合う制約を選びます。

氏名欄で全角空白だけも未入力にするなら、@NotBlankで同じ結果になるかを実際に確かめます。Hibernate Validator 8.0.3.Finalで全角空白1文字(U+3000)を検証すると違反は0件でした。この版はtrim()を使うため、全角空白が残ります。Java 17のisBlank()では同じ入力がtrueです。全角空白も拒否する仕様なら、使用中の版でFormに同じ値を渡すテストを追加し、必要に応じて入力制約を見直します。

関連記事Spring Bootで入力チェックが重複する|ControllerとServiceの分け方空文字や空白の形式チェックと、DB照合などの業務チェックをどこに置くかを具体例で確認できます。記事を読む

CSV・外部連携で空白を勝手に消さない

外部ファイルの空白が埋め文字なのか有効値なのかは連携仕様次第です。固定長ファイルでは右側空白を除去する一方、項目内の空白を維持することがあります。

String rawCode = row.code();
if (rawCode == null || rawCode.isBlank()) {
    errors.add("商品コードが未入力です");
} else {
    String code = rawCode.strip();
    validateCode(code);
}

検証用の値と保存する原文を分ける場合もあります。どの段階で正規化したかをログやエラー表示で追えるようにします。

状態表とテストで仕様を固定する

本文と同じコードをダウンロードする

実行用のJava、JUnitテスト、pom.xml、READMEを収録しています。ZIPを展開し、pom.xmlがある場所で java src/main/java/BlankStringDemo.java を実行すると8行の判定結果が表示されます。JDK 17とMaven 3.9系で mvn test を実行すると11件を確認できます。

サンプルZIPをダウンロード

氏名欄を想定し、null、空文字、Javaが空白とみなす文字だけの入力を未入力とします。次の全文をBlankStringDemo.javaに保存して、JDK 17でjava BlankStringDemo.javaを実行すると、冒頭の8行を表示できます。半角空白ではisEmptyがfalse、isMissingがtrueです。NBSPはこの判定では未入力扱いにならないため、拒否が必要なら入力仕様で指定します。

public class BlankStringDemo {
    static boolean isMissing(String value) {
        return value == null || value.isBlank();
    }

    public static void main(String[] args) {
        System.out.println("input\tisEmpty\tisBlank\tisMissing");
        printResult("null", null);
        printResult("empty", "");
        printResult("U+0020", " ");
        printResult("U+3000", "\u3000");
        printResult("TAB", "\t");
        printResult("LF", "\n");
        printResult("letters", " A ");
        printResult("U+00A0", "\u00A0");
    }

    private static void printResult(String label, String value) {
        String empty = value == null ? "NPE" : Boolean.toString(value.isEmpty());
        String blank = value == null ? "NPE" : Boolean.toString(value.isBlank());
        System.out.printf("%s\t%s\t%s\t%b%n", label, empty, blank, isMissing(value));
    }
}

出力のNPEは直接呼ぶと例外になる箇所を表します。JUnitでは、nullに判定を直接呼んで実際に例外が出ることを確かめます。

JUnitも動かす場合は、上の本体をsrc/main/java/BlankStringDemo.java、下のテストをsrc/test/java/BlankStringDemoTest.javaに置きます。pom.xmlをその親プロジェクトの直下に置き、同じ場所でJDK 17とMaven 3.9系を使ってmvn testを実行します。

BlankStringDemoTest.javaの全文を見る
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullAndEmptySource;
import org.junit.jupiter.params.provider.ValueSource;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

class BlankStringDemoTest {
    @ParameterizedTest
    @NullAndEmptySource
    @ValueSource(strings = {" ", "\u3000", "\t", "\n"})
    void 氏名の空入力を拒否する(String value) {
        assertTrue(BlankStringDemo.isMissing(value));
    }

    @Test
    void 文字を含む入力を受け付ける() {
        assertFalse(BlankStringDemo.isMissing(" A "));
    }

    @Test
    void NBSPだけの入力はこの判定では未入力にならない() {
        assertFalse(BlankStringDemo.isMissing("\u00A0"));
    }

    @Test
    void nullにStringの判定を直接呼ぶと例外になる() {
        String value = null;
        assertThrows(NullPointerException.class, () -> value.isEmpty());
        assertThrows(NullPointerException.class, () -> value.isBlank());
    }

    @Test
    void 全角空白はstripだけが取り除く() {
        assertEquals("\u3000", "\u3000".trim());
        assertEquals("", "\u3000".strip());
    }

    @Test
    void NBSPはtrimとstripのどちらにも残る() {
        assertEquals("\u00A0", "\u00A0".trim());
        assertEquals("\u00A0", "\u00A0".strip());
    }
}
pom.xmlの全文を見る
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>info.syachiku.samples</groupId>
  <artifactId>blank-string-input</artifactId>
  <version>1.0.0</version>
  <properties>
    <maven.compiler.release>17</maven.compiler.release>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <junit.version>5.12.2</junit.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter</artifactId>
      <version>${junit.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>3.2.0</version>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>3.5.6</version>
      </plugin>
    </plugins>
  </build>
</project>

テストは11件です。未入力6件と、文字あり・NBSPが未入力扱いにならない各1件、直接呼び出しの例外1件、trimとstripの比較2件を確認します。isMissingの中でvalue.isBlank()をvalue.isEmpty()へ変えて再実行すると、半角空白・全角空白・タブ・改行の4件が失敗します。元に戻して11件が通ることを確かめます。

バリデーションをテストするなら、単なるString判定だけでなくValidatorやMockMvcを通し、実際のエラーメッセージと再表示まで確認します。

現場レビューでよくある指摘

空入力のレビューではメソッド名だけでなく、対象項目で空白を有効とするか、正規化前後のどちらを保存するかを確認します。

// レビューコメント例
isEmptyではスペースだけの氏名が通ります。
必須項目の仕様に合わせてisBlankまたは@NotBlankを使ってください。

// レビューコメント例
valueがnullのときisBlankでNullPointerExceptionになります。
Controllerへ届く値の契約を確認し、境界で統一してください。

// レビューコメント例
全項目をtrimするとパスワードや固定長値まで変わります。
正規化対象の項目だけに限定してください。

『空ならエラー』という曖昧な仕様を、具体的な入力例へ置き換えます。画面、API、CSVで同じ項目の扱いが違う場合は、境界ごとのルールを明示します。

提出前のセルフチェック

レビュー前に確認すること

  • null・空文字・空白を区別したか
  • isEmptyとisBlankのどちらが仕様に合うか
  • nullへメソッドを呼んでいないか
  • 全角空白・タブ・改行を試したか
  • trimやstripの戻り値を使っているか
  • 空白を勝手に除去してよい項目か
  • Bean Validationで表現できないか
  • 画面とAPIとCSVで同じ契約か

文字列と入力検証を整理する参考書

String APIの基本とWeb入力の流れを合わせて学ぶと、null・空文字・空白の違いを場当たり的なif文で処理せずに済みます。

書籍「スッキリわかるJava入門 第5版」の表紙
商品画像:Amazon.co.jp
PR Java初学者向け

スッキリわかるJava入門 第5版

中山 清喬 (著), 国本 大悟 (著), 株式会社フレアリンク (監修)

変数・条件分岐から、クラスの基本まで学ぶ一冊。

豊富な図とサンプルで、変数、条件分岐、クラス、例外処理まで順番に学べます。Javaの最初の教科書を探している人向けです。

  • Javaを基礎から体系的に学びたい
  • Java 25 LTS対応の入門書を選びたい

当サイトはAmazonアソシエイト・プログラムの参加者です。価格・在庫・配送条件はAmazonでご確認ください。

この記事とあわせて読みたい

関連記事Javaのnullチェック入門nullの入口と、必須値・任意値を境界で扱う方法を確認できます。記事を読む 関連記事Spring Bootの@Validと@Validatedの違い|必須チェックが効かない原因と使い分け@NotBlankを選んでも検証されない場合に、@Valid・@Validatedとグループ指定を切り分けます。記事を読む

仕様の確認:Java 17 API — String(isEmpty・isBlank・trim・strip)。

まとめ

isEmptyは文字数0だけ、isBlankは空文字と空白文字だけの値をtrueと判定します。どちらもnullへ呼ぶとNullPointerExceptionです。

必須項目ならisBlankや@NotBlankが適することが多い一方、空白を有効とする項目もあります。null、空文字、各種空白の期待結果を具体化し、正規化する項目だけを限定してください。

-実装・エラー解決
-,