1
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?

【個人メモ】Javaの標準APIを学んで気づいた「なぜ?」をまとめてみた

1
Posted at

はじめに

Javaの標準API(日付・時刻、BigDecimal)を勉強したときに生まれた「なぜこうなっているの?」という疑問と、そこから得た新たな発見をまとめました。

1. staticメソッドとインスタンスメソッド

日付・時刻APIを使ううちに「なぜあるメソッドはクラスに対して呼び出し、別のメソッドは値に対して呼び出すのか?」という疑問が生まれました。

種類 構文
staticメソッド クラス名.メソッド名(引数) LocalDate.now()LocalDate.of(2021, 9, 14)
インスタンスメソッド 値.メソッド名(引数) today.plusDays(3)"abc".toUpperCase()
  • static → 「作る・共通処理」。インスタンスがなくても使える
  • インスタンス → 「使う・加工する」。手持ちの値に対して操作する
var today = LocalDateTime.now();   // staticで「今」を作る

today.plusDays(3)                  // インスタンスメソッドで加工する
today.plusWeeks(2)
today.plusHours(3)

💡 発見:使う人ではなく、作る人が意識する話
staticinstance かは、APIを設計する側が決める話です。使う側は「クラスに対して呼ぶのか、値に対して呼ぶのか」を覚えるだけです。

2. formattedとformatの違い

日付の整形メソッドは2種類ありました。

// インスタンスメソッド(Java 15〜)
"%tY年%<tm月%<td日".formatted(today)  // => "2021年06月25日"

// staticメソッド(昔からある書き方)
String.format("%tY年%<tm月%<td日", today)
メソッド 種類 構文
formatted インスタンスメソッド 書式.formatted(値)
format staticメソッド String.format(書式, 値)

⚠️ 注意:format は静かな罠がある
"%sですよ".format("みかん")"みかん" を返します。
formatString クラスのstaticメソッドなので、前の "%sですよ" という文字列は無視されています。String.format(...) と書くのが本来の使い方です。

3. BigDecimal

なぜ普通のdoubleじゃダメなのか

579 * 0.05  // => 28.950000000000003 ← 誤差が出る!

double は内部で2進数(IEEE 754規格) で数値を表現するため、10進数の小数を正確に表せないことがあります。

import java.math.BigDecimal;

var b579 = BigDecimal.valueOf(579);
var b005 = BigDecimal.valueOf(0.05);
b579.multiply(b005)  // => 28.95 ← 正確!

💡 発見:BigDecimalは10進数のまま保持する
double は「2進数に変換 → 計算 → 2進数から変換」という流れで誤差が生まれます。BigDecimalは10進数で保持するので変換の誤差がありません。
ただし、円周率のような無限小数はBigDecimalでも誤差が出ます。誤差がゼロではなく「10進数に変換できる数値なら正確」というイメージです。

コンストラクタの使い方に要注意

// ❌ これはダメ:double の誤差をそのまま引き継ぐ
new BigDecimal(0.05)
// => 0.05000000000000000277555756156289135105907917022705078125

// ✅ 文字列を渡す
new BigDecimal("0.05")  // => 0.05

// ✅ または valueOf を使う(精度は15桁程度まで)
BigDecimal.valueOf(0.05)

💡 発見:なぜ文字列を渡すのか?
double 型は2進数で表現されるので、0.05 という値をJVMに渡した瞬間にすでに誤差が乗っています。文字列で渡すことで、BigDecimalが10進数のまま受け取れる

4. なぜ新しいAPIはコンストラクタを使わせないのか

LocalDatenew では作れません。

LocalDate.of(2021, 9, 14)  // ✅ これはOK
new LocalDate(...)          // ❌ コンパイルエラー

💡 発見:ファクトリメソッドパターンという設計
新しいJavaのAPIには「コンストラクタを隠して、staticメソッド(ファクトリメソッド)でオブジェクトを作らせる」という傾向があります。
理由のひとつはメモリ効率です。同じ意味を持つオブジェクトが既にメモリにあれば、新たに生成せずそれを返せます。new を直接呼ぶとかならず新しいオブジェクトが生成されてしまって、参照できない(もともとあるものをリサイクルできない)ので非効率となります。

5. APIという言葉の多義性

💡 発見:「API」は文脈によって意味が変わる
Java標準ライブラリの文脈では「クラスやメソッド」のことをAPIと呼びますが、実際には大きく3種類あります。

  1. 同じプロセス内で呼び出す(Javaの標準ライブラリはこれ)
  2. 同じ機器内の別プロセスから呼び出す(UDS・共有メモリ経由)
  3. 異なる機器間でHTTPやRPCで呼び出す(いわゆるWeb API)

Web開発をすると「APIを叩く」という言葉が出てきますが、それは主に3番目の意味です。呼び出し元の言語も関係なく、呼び出し先がどう実装されているかも意識しなくていい、「共通の入り口」としてのAPIです。

おわりに

Java標準APIの学習を通じて気づいたことをまとめました。
API一つとっても色々な概念が登場して、面白いなと思いました。

1
0
1

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
1
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?