0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Effective Java 9.62: 他の型が適切な場所では、文字列を避ける

Posted at

9.62: 他の型が適切な場所では、文字列を避ける

結論

文字列(String)は便利だが 「なんでも文字列で扱う」のは悪手。
型の持つ意味(検査可能性、制約、操作メソッド、表現の明確さ)を活用できず、バグ・パフォーマンス低下・セキュリティ問題・可読性低下を招く。
値に意味があるなら適切な型を使うenumPathDurationInstantBigDecimalUUIDOptional、数値/真偽値 など)。


良い例

意味のある型を使って安全で読みやすい API にする例。

import java.math.BigDecimal;
import java.nio.file.Path;
import java.time.Duration;
import java.time.Instant;
import java.util.UUID;

public class OrderService {

    // 1) 通貨/金額は BigDecimal(または long cents)で扱う
    public void chargeCustomer(UUID customerId, BigDecimal amount) {
        // 金額の検証・丸めをここで行える
    }

    // 2) ファイルパスは Path にする(操作メソッドが豊富で型安全)
    public void importFrom(Path csvFile) {
        // Files.newBufferedReader(csvFile) などが直接使える
    }

    // 3) 時間は Duration / Instant を使う(パースや計算が簡単)
    public void scheduleJob(Instant when, Duration timeout) { ... }

    // 4) 識別子は UUID を使う(仕様が明確)
    public Order findOrder(UUID id) { ... }
}

利点:

  • コンパイル時に型の不整合を検出できる(早期発見)
  • API 利用者に期待値が明確(「この引数はいつか?」→ Instant
  • 標準 API・ユーティリティ(Path, Duration, BigDecimal 等)が使える(安全で効率的)

悪い例

すべて文字列で受け取ることによる典型的な問題。

public class BadApi {

    // NG: everything as String
    public void createOrder(String customerId, String amount, String when, String filePath) {
        // 呼び出し側が "2025-01-01T10:00:00Z" や "100.00" を渡すが、
        // どのフォーマットを期待しているかが不明で、実行時にパース失敗する可能性がある
    }
}

問題点の例:

  • customerId が UUID 形式でないと実行時エラー
  • amount にカンマや通貨記号が入ると NumberFormatException
  • when の日付フォーマットの違いで DateTimeParseException
  • filePath は OS 間で扱いが異なるが String だと意図しない操作が起きやすい
  • 全て文字列にするとドキュメントやテストが必須になり、使い手のミスを防げない

まとめ

  • 意味のある値には専用型を使う
    • 日付/時刻 → LocalDate / LocalDateTime / Instant
    • 期間 → Duration
    • パス → Path
    • 金額 → BigDecimal または スケール付き整数(long cents
    • 列挙される状態 → enum
    • 一意 ID → UUID(仕様上 UUID なら)
    • 真偽や数値 → boolean/int/long 等のプリミティブ
       
  • 文字列は“境界”だけに使う(JSON/HTTP/CLI の入出力やログ)。内部ロジックは型で扱う。
     
  • API の契約を明確にする:
    引数型を通じて期待フォーマット・制約を表現する。加えて Javadoc で補足する。
     
  • 変換・検証は入力境界で行う:
    文字列→型 のパース・妥当性チェックは受け口で行い、内部は常に正しい型を扱う。
     
  • 安全性と可読性が向上する設計を優先:
    SQL やコマンド構築で文字列結合を行うと注入脆弱性になる(PreparedStatement やパラメータ化を使う)。
     
  • コレクション内の文字列(CSV 等)は専用構造に:
    カンマ区切り String よりList<String>Set<String> を使う。
     
  • 互換性・シリアライズの必要がある場合は DTO を用意:
    外部とのやり取りは文字列ベースでも、内部には変換済み DTO/値オブジェクトを使う。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?