読み込み中...

Javaメソッド呼び出しの10選の秘訣!プログラミング初心者から上級者への道

Javaの他のクラスのメソッドを呼び出す方法の解説記事のサムネイル Java
この記事は約30分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Javaのメソッド呼び出しは、別クラスに分けた処理をnewで生成したinstanceから呼ぶ形、staticな処理をクラス名から呼ぶ形、interfaceabstract classを経由して差し替える形に整理できます。その整理ができると、プログラミング初心者でもサンプルコードの読み方が安定し、TypeScript、Python、JSとの違いも比較しやすくなります。

動作確認環境
  • Java 21 / javac 21
  • Maven 3.9.6 / Joda-Time 2.12.7
  • JSON-LD確認対象: Article / BreadcrumbList

そのため、Javaで最初に押さえる軸はclassmethodreturnparameteraccess modifierの関係です。OracleのDefining Methodsでは、メソッド宣言に戻り値、名前、括弧、本文が必要であることが説明されています。

📖 この記事で学べること
  • Javaで別クラスのメソッド呼び出しを行う基本形
  • インスタンス、static、interface、抽象クラスの使い分け
  • 例外、戻り値、ジェネリクス、ラムダ式を含むサンプルコード
  • NullPointerExceptionや可視性に関する注意点と対処法
  • カスタマイズしやすいメソッド設計と内部リンクで深掘りする観点

Javaとは:プログラミング言語の一環としての位置づけ

Javaは、クラスを中心にプログラムを組み立てるオブジェクト指向言語です。コンパイルされた.classファイルはJVM上で動くため、OS差を吸収しやすい構造になります。

一般に、Javaのコードはpublic class Mainのようなクラス定義から始まり、処理の入口としてpublic static void main(String[] args)を置きます。この入口から他のクラスを生成し、必要なメソッド呼び出しを重ねる流れが標準的です。

一方、TypeScriptやJSは関数を単体で書く場面も多く、Pythonもモジュール関数を柔軟に扱えますし、ここがポイントです。Javaはクラス境界を意識する時間が長いため、プログラミング初心者はfieldmethodconstructorobjectを早めに区別すると理解が進みます。

分類Javaでの形使う場面注意点関連語
通常メソッドobj.run()状態を使う処理null参照に注意instance
staticUtil.add()状態を使わない処理依存が固定化しやすいstatic
オーバーロードprint(int)同名で引数違い戻り値だけでは区別不可signature
interfaceAction a実装を差し替える処理契約を小さく保つimplements
抽象クラスextends Base共通処理を持つ継承階層を深くしすぎないabstract
例外throws異常系の伝達握りつぶさないtry/catch
戻り値return value計算結果の受け渡し型を明確にするreturn
voidvoid log()表示や更新だけの処理副作用が読みにくい場合ありvoid
privateprivate voidクラス内部だけ外部から呼べないprivate
protectedprotected void継承先で使う処理公開範囲が広がるprotected
publicpublic void外部APIにする処理変更の影響が大きいpublic
指定なしvoid run()同一パッケージ内意図を名前で補うpackage
コンストラクタnew Person()初期値を渡す重い処理を避けるconstructor
thisthis.name自分のフィールド参照引数名との混同を避けるthis
supersuper.run()親の処理を使う親子の責務を分けるsuper
配列String[]同型データの並び長さ固定array
ListList<String>可変長の並び型引数を明示List
ジェネリクス<T>型安全な共通処理実行時の型消去generic
ラムダ式() -> {}短い処理の受け渡し読みやすさを確認lambda
メソッド参照System.out::println既存処理の受け渡し引数型を合わせる::
OptionalOptional<T>nullの明示フィールド濫用を避けるOptional
StringString文字列処理不変オブジェクトisEmpty()
StringBuilderStringBuilder文字列の連結共有に注意append()
Mavenpom.xml依存関係管理バージョンを固定dependency
packagepackage app;名前空間の分離ディレクトリと一致package
importimport java.util.*外部クラスの参照ワイルドカードを避ける場合ありimport
finalfinal int再代入防止参照先の不変とは別final
enumenum Status固定値の集合文字列比較を減らすenum
recordrecord User()値オブジェクトJava 16以降record
varvar nameローカル変数の型推論可読性を確認var

これらをまとめて見ると、Javaのメソッド呼び出しは構文暗記だけではなく、どのクラスに責務を置くかという設計判断とつながります。オーバーライドの考え方を合わせて読むと、継承時の呼び出し関係も整理できます。

Javaの特徴と基本概念

Javaの特徴は、classにデータと処理をまとめ、必要に応じて別クラスから呼び出す点にあるのが基本です。encapsulationで内部状態を隠し、publicなメソッドだけを外へ出すと、変更に強い構成になります。

ただし、すべてをクラスに分ければ読みやすくなるわけではありません。プログラミング初心者がつまずきやすいのは、処理を分けたあとにどのオブジェクトを生成し、どの変数から呼ぶのかが追えなくなる場面です。

💡 Tips: メソッド名は動詞から始めると読みやすくなります。たとえばcalculateTotalfindUserprintReportのように、呼び出し側の文脈で処理内容が伝わる名前を選びますが、これは押さえたい点です。

他のクラスのメソッドを呼び出す基本

Javaで他のクラスの処理を使う最小形は、呼び出したいクラスをnewで生成し、変数名の後ろに.とメソッド名を書く形です。メソッド呼び出しの対象がstaticなら、インスタンスではなくクラス名から直接呼びます。

class Greeting { void sayHello() { System.out.println("Hello"); } } public class Main { public static void main(String[] args) { Greeting greeting = new Greeting(); greeting.sayHello(); } }

結果: 期待される出力はHelloです。JavaではGreetingのインスタンスを作成し、greeting.sayHello()で別クラスのメソッド呼び出しを行います。

このとき、呼び出し先のメソッドがprivateであれば別クラスからは呼べません。publicprotected、パッケージプライベートの違いは、Javaアノテーションの使い方と同じく、コードの読み手に意図を伝える手がかりになるのが目安です。

オブジェクト指向プログラミングの基本

オブジェクト指向では、関連するデータと処理を同じクラスに置きます。そのため、Javaのメソッド呼び出しは単なる命令実行ではなく、オブジェクトに仕事を依頼する書き方になります。

具体的には、Personに名前を持たせ、greet()で挨拶を作るように責務を閉じ込めますし、これが一つの目安です。TypeScriptやPythonでも似た設計は可能ですが、Javaはコンパイル時の型チェックが強く、呼び出しミスが早めに表面化します。

クラスとメソッドを初心者向けに整理

クラスは設計図、インスタンスは設計図から作った実体、メソッドは実体が持つ操作です。この関係を押さえると、A a = new A()の左辺が型、右辺が生成、a.work()が呼び出しだと読めます。

ただし、staticメソッドは実体に属さずクラスに属するのがポイントです。JSの関数呼び出しやPythonのモジュール関数に近く見える場面もありますが、JavaではClassName.methodName()という形で所属を明示します。

実践!Javaで他のクラスのメソッドを呼び出す10選の方法

Javaのメソッド呼び出しは、基本形、オーバーロード、インスタンス、static、interface、抽象クラス、例外、戻り値、ジェネリクス、ラムダ式に分けると理解しやすくなります。各サンプルコードは、呼び出し先と呼び出し元の関係が見えるように短くまとめているのが一般的です。

サンプルコード1:メソッドの基本的な呼び出し方

基本形では、処理を持つクラスを作り、別のクラスのmainからインスタンス経由で呼びます。Javaの学習初期は、この形を手で書けるようにすると後続の構文も読みやすくなります。

public class Greeting { public void sayHello() { System.out.println("Hello, World!"); } } public class Main { public static void main(String[] args) { Greeting greeting = new Greeting(); greeting.sayHello(); } }

結果: 期待される出力はHello, World!です。new Greeting()で作った参照からsayHello()を呼びますが、覚えておくと役立つでしょう。

このサンプルコードは、Javaのメソッド呼び出しで最も小さい単位です。Greetingの内部実装を変更しても、publicなメソッド名が変わらなければ呼び出し元の形は保てます。

サンプルコード2:メソッドオーバーロードの利用

オーバーロードは、同じメソッド名に対して引数の型や数を変える書き方です。公式ドキュメントによれば、Javaは異なるメソッドシグネチャを区別できるため、同名メソッドを複数持てます。

public class Example { public void display(int a) { System.out.println("整数: " + a); } public void display(String b) { System.out.println("文字列: " + b); } public void display(int a, String b) { System.out.println("整数と文字列: " + a + ", " + b); } }

結果: この定義だけでは出力はありません。期待される効果は、displayの引数に応じてJavaコンパイラが呼び出すメソッドを選ぶことです。

public class Main { public static void main(String[] args) { Example example = new Example(); example.display(1); example.display("テスト"); example.display(1, "テスト"); } }

結果: 期待される出力は整数、文字列、整数と文字列の順です。戻り値だけを変えた同名メソッドは区別できない点が注意点になります。

整数: 1 文字列: テスト 整数と文字列: 1, テスト

結果: これは期待される出力例です。実際のJavaコードでは、display(int)display(String)display(int, String)の順に対応します。

ただし、似た意味のオーバーロードを増やしすぎると、プログラミング初心者には候補が追いにくくなるのが現実的です。TypeScriptの関数オーバーロードと同様に、呼び出し側が迷わない名前と引数設計を優先します。

サンプルコード3:インスタンスメソッドの呼び出し

インスタンスメソッドは、オブジェクトごとの状態を使う処理に向いています。Javaではprivate String nameのようなフィールドを持たせ、コンストラクタで値を受け取る形がよく使われますし、ここを基本と考えるとよいでしょう。

public class Person { private String name; public Person(String name) { this.name = name; } public void greet() { System.out.println("こんにちは、" + name + "さん"); } }

結果: この定義だけでは表示はありません。Personnameを保持し、greet()が呼ばれたときに名前を使う準備をします。

public class Main { public static void main(String[] args) { Person person = new Person("田中"); person.greet(); } }

結果: 期待される出力はこんにちは、田中さんです。personが持つnameを使って、Javaのインスタンスメソッドが処理します。

サンプルコード4:スタティックメソッドの利用

staticメソッドは、オブジェクトごとの状態を使わない処理に向いていると整理できます。計算、文字列整形、日付変換などの小さなユーティリティでは、JavaでもUtil.add(3, 5)のような呼び出しが見られます。

public class Util { public static int add(int a, int b) { return a + b; } }

結果: この定義だけでは出力はありません。staticが付いたaddは、インスタンスを作らずクラス名から呼べます。

public class Main { public static void main(String[] args) { int result = Util.add(3, 5); System.out.println("結果は: " + result); } }

結果: 期待される出力は結果は: 8です。状態を持たない計算なら、Javaのstaticなメソッド呼び出しで簡潔に書けると理解できます。

ただし、何でもstaticに寄せるとテスト時の差し替えやカスタマイズが難しくなります。JSの純粋関数やPythonのモジュール関数に近い使い方を意識しつつ、状態を持つ処理はインスタンスへ寄せます。

サンプルコード5:インターフェイスを用いたメソッドの呼び出し

interfaceは、呼び出し側が具体的なクラス名に依存しないための契約です。Javaで拡張しやすい設計を作るとき、implementsを使うメソッド呼び出しはよく使われますし、ここがポイントです。

public interface Action { void perform(); }

結果: この定義だけでは出力はありません。Actionperform()を持つという契約を表します。

public class HelloAction implements Action { @Override public void perform() { System.out.println("Hello, World!"); } }

結果: この定義だけでは表示されません。HelloActionActionの契約に従い、perform()の具体処理を持ちます。

public class Main { public static void main(String[] args) { Action action = new HelloAction(); action.perform(); } }

結果: 期待される出力はHello, World!です。変数の型をActionにすることで、呼び出し側は実装クラスの詳細から離れられますが、これは押さえたい点です。

この設計は、TypeScriptのinterfaceやPythonの抽象基底クラスに近い考え方です。Javaでは@Overrideを付けることで、メソッド名や引数のずれをコンパイル時に検出しやすくなります。

サンプルコード6:抽象クラスを用いたメソッドの呼び出し

抽象クラスは、共通処理と未完成の処理を同じ親クラスに置ける仕組みです。Javaではabstractを付けたクラスを直接newできないため、具体クラスを作ってからメソッド呼び出しを行います。

public abstract class AbstractClass { public abstract void abstractMethod(); } public class ConcreteClass extends AbstractClass { @Override public void abstractMethod() { System.out.println("抽象メソッドの具体的な実装"); } }

結果: この定義だけでは出力はありません。ConcreteClassabstractMethod()を実装することで呼び出せる状態になると覚えるとよいでしょう。

public class Main { public static void main(String[] args) { ConcreteClass concreteClass = new ConcreteClass(); concreteClass.abstractMethod(); } }

結果: 期待される出力は抽象メソッドの具体的な実装です。親の型で契約を作り、子クラスで実装を確定します。

サンプルコード7:例外処理とメソッド呼び出し

例外処理では、呼び出し先で起きた異常を呼び出し元が受け取ります。Javaのthrowsthrowtrycatchの関係を読むと、どこで失敗を扱うかが明確になると考えられます。

try { /* エラーが発生する可能性のあるコード */ } catch (Exception e) { /* 例外発生時の処理 */ }

結果: これは構文の雛形なので単体では実行できません。期待される役割は、try内の失敗をcatchで受けることです。

public class Main { public static void main(String[] args) { try { SampleClass sample = new SampleClass(); sample.sampleMethod(); } catch (CustomException e) { System.out.println("カスタム例外が発生しました: " + e.getMessage()); } } } class SampleClass { void sampleMethod() throws CustomException { throw new CustomException("これはカスタム例外です"); } } class CustomException extends Exception { public CustomException(String message) { super(message); } }

結果: 期待される出力はカスタム例外が発生しました: これはカスタム例外ですです。呼び出し先のsampleMethod()が例外を投げ、呼び出し元が処理します。

⚠️ 注意: 例外を空のcatchで無視すると、障害の原因が追えなくなります。ログ出力、再送、利用者向けメッセージなど、呼び出し元で必要な対処法を決めておく必要があると言えるでしょう。

サンプルコード8:メソッドの戻り値の活用

戻り値は、呼び出し先の処理結果を呼び出し元へ返す仕組みです。Javaではメソッド宣言時にintStringbooleanvoidなどの戻り値型を書きます。

public class Main { public static int add(int a, int b) { int sum = a + b; return sum; } public static void main(String[] args) { int result = add(3, 5); System.out.println("結果:" + result); } }

結果: 期待される出力は結果:8です。returnで返した値をresultに入れ、呼び出し元で利用します。

この形は、Java List型の処理でもよく出てきますし、これが一つの目安です。リストを受け取って合計や検索結果を返す設計にすると、メソッド単体の責務が見えやすくなります。

サンプルコード9:ジェネリクスを活用したメソッドの呼び出し

ジェネリクスは、型を引数のように扱う仕組みです。Javaの<T>を使うと、同じメソッドでIntegerStringを扱いながら、型安全性を保てます。

public class GenericMethodExample { public static <T> void display(T element) { System.out.println("Element: " + element); } public static void main(String[] args) { display(123); display("Javaプログラミング"); } }

結果: 期待される出力はElement: 123Element: Javaプログラミングです。Javaの型推論により、呼び出し時の値からTが決まりますが、覚えておくと役立つでしょう。

public class GenericClassExample<T> { private T item; public void setItem(T item) { this.item = item; } public T getItem() { return item; } public static void main(String[] args) { GenericClassExample<String> s = new GenericClassExample<>(); s.setItem("Javaジェネリクス"); System.out.println("Item: " + s.getItem()); } }

結果: 期待される出力はItem: Javaジェネリクスです。setItem()getItem()が同じ型でつながるため、型の取り違えを抑えられます。

サンプルコード10:ラムダ式とメソッド参照の活用

ラムダ式は、短い処理を値のように渡すための構文です。JavaではRunnableConsumerFunctionなどの関数型インターフェイスと組み合わせます。

Runnable runLambda = () -> { System.out.println("ラムダ式を使用したRunnableの実装"); }; runLambda.run();

結果: 期待される出力はラムダ式を使用したRunnableの実装です。() ->の左側が引数、右側が処理本体になるのが基本です。

List<String> items = Arrays.asList("apple", "banana", "cherry"); items.forEach(System.out::println);

結果: 期待される出力はapplebananacherryの順です。System.out::printlnは、各要素を出力するメソッド参照です。

この書き方はJSのコールバックやPythonの高階関数に近い感覚で読めます。ただし、Javaでは対象となる関数型インターフェイスの引数型と戻り値型に合う必要があります。

応用例とサンプルコード

基本形が分かると、複数クラスの連携や外部ライブラリの利用に進めますし、ここを基本と考えるとよいでしょう。Javaのメソッド呼び出しは、処理を分割しながら組み合わせるための接点なので、サンプルコードでは依存の向きも確認します。

応用1:複数クラスの組み合わせ

複数クラスを組み合わせる場合、呼び出し元が呼び出し先を直接生成する方法があります。小さな学習コードでは読みやすい一方、実務的なアプリケーションではDIコンテナやファクトリで依存を渡す構成も使われますし、ここがポイントです。

class ClassA { void methodA() { System.out.println("ClassAのmethodAが呼び出されました。"); } } class ClassB { ClassA classA = new ClassA(); void callMethodAFromB() { classA.methodA(); } } public class Sample { public static void main(String[] args) { ClassB classB = new ClassB(); classB.callMethodAFromB(); } }

結果: 期待される出力はClassAのmethodAが呼び出されました。です。ClassBのメソッドがClassAのメソッド呼び出しを包みます。

その構成では、利用者はClassAを直接知らなくてもClassB経由で処理を使えます。うるう年判定のような条件分岐も、判定クラスと表示クラスを分けると読みやすくなるのが目安です。

応用2:外部ライブラリを利用したメソッドの呼び出し

外部ライブラリを使う場合、Mavenのpom.xmlに依存関係を追加し、importでクラスを参照します。元記事ではJoda-Timeを扱っていましたが、Java 8以降の標準APIにはjava.timeがあるため、新規開発では標準APIも検討対象になります。

<dependency><groupId>joda-time</groupId><artifactId>joda-time</artifactId><version>2.12.7</version></dependency>

結果: Mavenプロジェクトでは、期待される効果としてJoda-Timeのクラスを参照できるようになるのがポイントです。依存関係のバージョンはプロジェクト方針に合わせて固定します。

import org.joda.time.LocalDate; public class DateSample { public static void main(String[] args) { LocalDate currentDate = LocalDate.now(); System.out.println("今日の日付は: " + currentDate); } }

結果: 期待される出力は実行日のローカル日付を含む文字列です。日付は環境の日付に依存するため、固定の出力値として断定しません。

一方、現在のJava標準ではjava.time.LocalDateも使えます。OracleのString APIドキュメントのように、標準ライブラリの仕様は一次情報で確認すると安全です。

注意点と対処法

Javaのメソッド呼び出しで起きやすい問題は、可視性、null、循環呼び出し、例外処理に集約できます。注意点と対処法をセットで押さえると、サンプルコードを自分のコードへ移すときの失敗を減らせますが、これは押さえたい点です。

注意点1:メソッドの可視性

可視性は、メソッドをどこから呼べるかを決めます。Javaではpublicprotected、指定なし、privateの範囲が異なり、APIとして外へ出す処理ほど変更の影響が広がります。

public class VisibilityDemo { public void publicMethod() { System.out.println("Public method"); } protected void protectedMethod() { System.out.println("Protected method"); } void defaultMethod() { System.out.println("Default method"); } private void privateMethod() { System.out.println("Private method"); } }

結果: この定義だけでは出力はありません。期待される効果は、呼び出し元の場所によりアクセス可能なメソッドが変わることです。

そのため、外部から呼ぶ必要がない処理はprivateへ寄せます。プログラミング初心者は、最初からすべてをpublicにせず、呼び出し元を具体的に想定してから公開範囲を決めると整理しやすくなります。

注意点2:NullPointerExceptionの対処法

NullPointerExceptionは、参照がnullの状態でメソッドやフィールドへアクセスしたときに発生するのが一般的です。JavaのString APIでも、特に断りがない限りnull引数でNullPointerExceptionが起きる旨が示されています。

public class NullPointerExceptionDemo { public static void main(String[] args) { String str = null; if (str != null) { System.out.println(str.toUpperCase()); } else { System.out.println("The string is null"); } } }

結果: 期待される出力はThe string is nullです。str != nullを確認してからtoUpperCase()を呼ぶため、例外を避けられます。

その対処法として、入力直後にnullを拒否する、Optionalで存在しない値を表す、空文字とnullを混同しない、といった設計があるのが現実的です。文字列の扱いはエスケープ処理とも関係するため、境界値を早めに決めます。

注意点3:メソッドの循環参照

循環呼び出しは、メソッド同士が終わりなく呼び合う状態です。Javaでは再帰が深くなりすぎるとStackOverflowErrorにつながるため、終了条件や依存方向を設計時に確認します。

public class CircularReferenceDemo { public static void main(String[] args) { methodA(); } public static void methodA() { methodB(); } public static void methodB() { methodA(); } }

結果: 期待される挙動は、methodA()methodB()が相互に呼ばれ続けることです。実行環境によっては最終的にStackOverflowErrorが発生すると整理できます。

⚠️ 注意: 循環呼び出しを学習目的で確認する場合でも、無限に近い処理になります。通常のアプリケーションコードへ入れず、終了条件や呼び出し方向を明確にした形へ直します。

対処法1:コードの整理とリファクタリング

処理が長くなったら、意味のある単位でメソッドへ切り出すると理解できます。JavaではsumOfNumbersのように処理名を付けると、呼び出し元のmainが流れを読む場所になり、計算の詳細は別メソッドへ移ります。

public class RefactoringDemo1 { public static void main(String[] args) { int result = 0; for (int i = 0; i < 10; i++) { result += i; } System.out.println("The result is: " + result); } }

結果: 期待される出力はThe result is: 45です。処理は正しくても、合計計算と表示がmainに混在しています。

public class RefactoringDemo2 { public static void main(String[] args) { int result = sumOfNumbers(10); System.out.println("The result is: " + result); } public static int sumOfNumbers(int n) { int result = 0; for (int i = 0; i < n; i++) { result += i; } return result; } }

結果: 期待される出力はThe result is: 45です。sumOfNumbers(10)というメソッド呼び出しにより、計算処理の意味が呼び出し側へ表れます。

対処法2:適切な例外処理

例外処理では、失敗した事実と原因を呼び出し元へ伝えることが中心になります。JavaのArithmeticExceptionのような実行時例外でも、利用者へ返すメッセージやログの残し方は設計対象です。

public class ExceptionHandlingDemo { public static void main(String[] args) { try { int result = divide(10, 0); System.out.println("The result is: " + result); } catch (ArithmeticException e) { System.out.println("An error occurred: " + e.getMessage()); } } public static int divide(int a, int b) throws ArithmeticException { return a / b; } }

結果: 期待される出力はAn error occurred: / by zeroです。divide(10, 0)で発生した例外をcatchで受けます。

ただし、例外を出すこと自体が目的ではありません。入力値の事前チェック、業務上のエラー表現、ログ出力の粒度を決めてから、必要な範囲でthrowthrowsを使います。

カスタマイズの方法

Javaのメソッド呼び出しをカスタマイズする場合、既存クラスを直接変更するのではなく、ユーティリティクラス、ラッパークラス、interface、デザインパターンで拡張点を作りますし、これが一つの目安です。カスタマイズの目的は、呼び出し側のコードを読みやすく保ちながら、変更範囲を小さくすることです。

カスタマイズ例1:メソッドの拡張

JavaのStringfinalクラスなので、継承でメソッドを追加する設計はできません。そのため、文字列処理を追加したい場合はStringExtensionsのようなユーティリティクラスを作り、staticメソッドとして呼び出す形が扱いやすくなります。

public class StringExtensions { public static String reverse(String str) { if (str == null || str.isEmpty()) { return str; } char[] chars = str.toCharArray(); int left = 0; int right = chars.length - 1; while (left < right) { char temp = chars[left]; chars[left] = chars[right]; chars[right] = temp; left++; right--; } return new String(chars); } }

結果: この定義だけでは出力はありません。期待される効果は、StringExtensions.reverse("abc")のようなメソッド呼び出しで文字列を反転できることです。

このカスタマイズでは、nullと空文字を先に返すため、呼び出し元の対処法も単純になります。Javaの標準Stringを変更せず、別クラスに処理を分ける点が安全です。

カスタマイズ例2:デザインパターンの活用

デザインパターンは、繰り返し出てくる設計課題への定型的な解き方です。Javaでシングルトンを使うと、設定や共有リソースのようにインスタンスを一つに絞りたい場面を表現できます。

public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }

結果: この定義だけでは出力はありません。期待される効果は、外部からnew Singleton()できず、getInstance()経由で同じインスタンスを得ることです。

ただし、この単純なシングルトンはマルチスレッド環境で競合する可能性があります。実装パターンとしてよく見るのは、enumシングルトン、初期化ホルダー、DIコンテナで管理する方式です。

ℹ️ 補足: カスタマイズは、既存APIの置き換えではなく呼び出し方の統一として考えると安定します。TypeScript、Python、JSでも同じく、共通処理を小さな関数やクラスに閉じ込める設計が読みやすさにつながりますが、覚えておくと役立つでしょう。

まとめ

Javaのメソッド呼び出しは、インスタンス経由、クラス名経由、interface経由、抽象クラス経由という視点で分けると迷いにくくなります。プログラミング初心者は、最初にnew.returnstaticの役割を押さえ、サンプルコードの呼び出し元と呼び出し先を線で追うと理解しやすいです。

そのうえで、注意点と対処法をセットにすると、可視性の誤り、null参照、循環呼び出し、例外処理の抜けを減らせます。JavaだけでなくTypeScript、Python、JSでも、責務を分けて名前の分かるメソッドにする考え方は共通していると覚えるとよいでしょう。

具体的には、状態を使うならインスタンスメソッド、状態を使わない小さな処理ならstatic、差し替えたい処理ならinterface、共通処理を持つ継承なら抽象クラスが候補になります。カスタマイズを加える場合も、呼び出し側の読みやすさを保つ形で設計すると、Javaのコード全体が追いやすくなります。

関連記事

著者: Japanシーモア編集部

Japanシーモアは、Web/IoT/APP/SYS 分野のプログラミング情報を体系的に提供するメディアです。本記事は編集部による執筆とAI支援を組み合わせて制作し、公開前に編集部が校正しています。誤りや改善案がございましたらお問い合わせよりご連絡ください。

※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。