Kotlinのデフォルト引数活用法10選

Kotlinのデフォルト引数を用いたコード例のスクリーンショットKotlin
この記事は約15分で読めます。

 

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

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

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

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

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

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

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

はじめに

Kotlinを学んでいると、さまざまな便利な機能に出会います。

その中でも、デフォルト引数はKotlinの美点の一つと言えるでしょう。

この記事を読めば、Kotlinのデフォルト引数を活用する方法を完璧にマスターすることができます。

プログラミング初心者の方から中級者の方まで、実際のサンプルコードを通じてデフォルト引数の魅力をお伝えします。

●Kotlinのデフォルト引数とは

Kotlinでは、関数やコンストラクタで引数を受け取る際、その引数に初期値を設定することができます。

この初期値を持つ引数を「デフォルト引数」と言います。

デフォルト引数を設定することで、関数やコンストラクタを呼び出す際に、その引数を省略することができます。

この機能はコードの可読性を高めるだけでなく、多重定義を減らす効果もあります。

○デフォルト引数の基本

デフォルト引数は、関数の定義時に引数に= (初期値)という形式で設定します。

この初期値が設定された引数は、関数呼び出し時に省略可能となります。

もし引数を省略した場合、設定された初期値がその引数の値として使用されます。

このデフォルト引数の特性により、関数のオーバーロードを減少させたり、呼び出し側のコードの記述をシンプルに保つことができます。

例えば、ある関数が複数の引数を持っていて、それぞれに適切な初期値が設定されている場合、関数を呼び出す際に全ての引数を指定する必要はありません。

必要な引数のみを指定して、他はデフォルト値に任せることができます。

これにより、関数の利用が非常に柔軟となります。

また、デフォルト引数は、関数の引数の中でもどの位置にでも設定することができます。

最初の引数にも、最後の引数にも、またはそれらの間の任意の位置にもデフォルト引数を設定することが可能です。

●デフォルト引数の使い方

Kotlinでは、デフォルト引数を使用して関数の柔軟性を大幅に向上させることができます。

デフォルト引数を上手く利用することで、関数呼び出し時の手間を減らし、コードの可読性や保守性を高めることが可能です。

○サンプルコード1:」デフォルト引数を持つ関数の定義

デフォルト引数を持つ関数の定義は非常に簡単です。

ここでは、greetという関数で、nameという引数が"World"というデフォルト値を持つ例を紹介します。

fun greet(name: String = "World") {
    println("Hello, $name!")
}

このコードでは、greet関数はnameという引数を取りますが、引数が指定されない場合はデフォルトの"World"が使用されます。

この関数を呼び出すと、Hello, World!と出力されるのが期待されます。

○サンプルコード2:デフォルト引数の上書き

デフォルト引数を持つ関数を呼び出す際、そのデフォルト引数を上書きして別の値を指定することもできます。

前述のgreet関数を利用して、デフォルト引数を上書きしてみましょう。

greet("Kotlin")

このコードを実行すると、Hello, Kotlin!という出力結果が得られます。

デフォルトの"World"ではなく、指定した"Kotlin"name引数の値として使用されました。

○サンプルコード3:複数のデフォルト引数を持つ関数

Kotlinでは、1つの関数に複数のデフォルト引数を設定することができます。

これにより、関数を呼び出す際の柔軟性が増し、必要に応じて引数を省略したり上書きしたりすることができます。

ここでは、introduceという関数で、firstName, lastName, ageという3つの引数がそれぞれデフォルト値を持つ例を表しています。

fun introduce(firstName: String = "John", lastName: String = "Doe", age: Int = 20) {
    println("$firstName $lastName, $age 歳です。")
}

このコードでは、引数がすべて省略された場合、デフォルト値を使用して"John Doe, 20 歳です。"と出力されることが期待されます。

一方、必要に応じて1つだけ、または複数の引数を上書きして関数を呼び出すこともできます。

○サンプルコード4:名前付き引数との組み合わせ

デフォルト引数は名前付き引数との組み合わせで、特に強力になります。

名前付き引数を使用することで、関数を呼び出す際に、引数の順序を気にせずに指定することができるため、どの引数を上書きするかを明示的に選ぶことができます。

前述のintroduce関数を用いて、lastNameageだけを上書きして関数を呼び出す例を紹介します。

introduce(lastName = "Smith", age = 25)

このコードを実行すると、"John Smith, 25 歳です。"という出力結果が得られます。

デフォルトの"Doe"20ではなく、指定した"Smith"25がそれぞれlastNameageの引数として使用されました。

○サンプルコード5:デフォルト引数を持つコンストラクタ

Kotlinでは、クラスのコンストラクタもデフォルト引数を持たせることが可能です。

これにより、オブジェクトのインスタンスを作成する際に、一部の情報のみを指定して、残りをデフォルト値として使用することができます。

デフォルト引数を持つコンストラクタは、特にデータクラスなどでの利用が見られます。

class Person(val name: String = "山田", val age: Int = 25) {
    fun show() {
        println("$name さんは $age 歳です。")
    }
}

val person1 = Person()
person1.show()

val person2 = Person("佐藤", 30)
person2.show()

val person3 = Person(age = 28)
person3.show()

このコードでは、Personというクラスを定義し、nameageの2つのプロパティにデフォルト引数を持たせています。

その結果、インスタンスを作成する際に引数を省略するとデフォルトの"山田"25が採用されます。

コードの実行により、それぞれのshowメソッドが次のように出力されることを期待しています。

山田 さんは 25 歳です。
佐藤 さんは 30 歳です。
山田 さんは 28 歳です。

●デフォルト引数の応用例

Kotlinのデフォルト引数は、単なる関数やコンストラクタだけでなく、さまざまな場面でその力を発揮します。

ここでは、デフォルト引数の応用例として、データクラスや拡張関数での使用方法を取り上げます。

○サンプルコード6:デフォルト引数を利用したデータクラス

データクラスは、Kotlinの特徴的なクラスの一つで、主にデータの格納や取り扱いに特化しています。

デフォルト引数を使用することで、データクラスのインスタンス生成時に、部分的な情報のみを指定可能となります。

data class Book(val title: String = "未定", val author: String = "不明", val price: Int = 0)

val book1 = Book()
println(book1)

val book2 = Book("Kotlin入門", "田中太郎")
println(book2)

val book3 = Book(price = 1500)
println(book3)

このコードでは、Bookというデータクラスを定義しており、3つのプロパティにデフォルト引数を設定しています。

コードを実行すると、次のような出力結果が得られます。

Book(title=未定, author=不明, price=0)
Book(title=Kotlin入門, author=田中太郎, price=0)
Book(title=未定, author=不明, price=1500)

○サンプルコード7:デフォルト引数を用いた拡張関数

Kotlinには、既存のクラスに新しい関数を追加する「拡張関数」という機能ががあります。

この拡張関数にもデフォルト引数を使用することができます。

fun String.repeatString(times: Int = 1): String {
    return this.repeat(times)
}

println("Kotlin".repeatString())
println("Kotlin".repeatString(3))

上記のコードでは、StringクラスにrepeatStringという拡張関数を追加しています。

この関数は、文字列を指定された回数だけ繰り返す役割を持っており、デフォルト引数を使って繰り返し回数を設定しています。

このコードを実行すると、次の結果が出力されることが期待されます。

Kotlin
KotlinKotlinKotlin

○サンプルコード8:デフォルト引数の継承とオーバーライド

Kotlinでは、デフォルト引数を持つ関数やプロパティを継承する際、そのデフォルト値をどのように取り扱うかが一つのテーマとなります。

継承関係にあるクラス間でのデフォルト引数の挙動を理解することは、意図しないバグを防ぐ上で重要です。

例として、動物を表す基底クラスAnimalと、そのサブクラスDogを考えます。

基底クラスでは動物の名前を受け取る関数introduceを持ち、サブクラスDogではこの関数をオーバーライドします。

open class Animal {
    open fun introduce(name: String = "動物") {
        println("私は$name です。")
    }
}

class Dog : Animal() {
    override fun introduce(name: String = "犬") {
        super.introduce(name)
    }
}

val animal = Animal()
animal.introduce() // 出力: 私は動物 です。

val dog = Dog()
dog.introduce() // 出力: 私は犬 です。

このコードでは、Animalクラスにintroduce関数を定義し、デフォルト引数として”動物”を設定しています。

Dogクラスでは、この関数をオーバーライドし、デフォルト引数として”犬”を設定しています。

コードを実行すると、Dogクラスのインスタンスでintroduce関数を呼び出した際、オーバーライドされた関数のデフォルト引数が使用されることが確認できます。

ここで注目すべきは、オーバーライドする際にも、デフォルト引数を明示的に指定する必要がある点です。

オーバーライドされた関数のデフォルト引数は、基底クラスのデフォルト引数とは独立して扱われます。

○サンプルコード9:デフォルト引数とラムダ式

ラムダ式は、Kotlinで関数を簡潔に記述するための方法の一つです。

デフォルト引数と組み合わせることで、ラムダ式を使った関数の呼び出しをより柔軟に行うことができます。

例えば、ある数値のリストに対して、条件に合致する数値だけを取り出したい場合を考えます。

このようなフィルタリング操作は、ラムダ式を用いて簡潔に記述することができます。

fun List<Int>.customFilter(predicate: (Int) -> Boolean = { it > 0 }): List<Int> {
    return this.filter(predicate)
}

val numbers = listOf(-3, -2, -1, 0, 1, 2, 3)
val positiveNumbers = numbers.customFilter()
println(positiveNumbers) // [1, 2, 3]

val evenNumbers = numbers.customFilter { it % 2 == 0 }
println(evenNumbers) // [-2, 0, 2]

このコードでは、Intのリストに対する拡張関数customFilterを定義しています。

この関数は、数値が条件に合致するかどうかを判定するラムダ式を受け取る引数predicateを持っており、この引数にはデフォルト引数として正の数値を取り出すラムダ式が設定されています。

コードを実行すると、デフォルト引数を使って正の数値だけを取り出す操作と、指定したラムダ式を使って偶数だけを取り出す操作の両方が行われることが確認できます。

○サンプルコード10:高階関数とデフォルト引数の組み合わせ

高階関数は、関数を引数として受け取るか、関数として結果を返す関数のことを指します。

Kotlinではこの高階関数とデフォルト引数を組み合わせることで、より柔軟で読みやすいコードを実現することができます。

例えば、あるリストの各要素に対して特定の操作を実行し、その結果を新たなリストとして返す関数を考えます。

このとき、特定の操作をデフォルトの関数として指定し、必要に応じてこのデフォルトの関数を上書きすることを想定します。

fun <T> List<T>.applyOperation(operation: (T) -> T = { it }): List<T> {
    return this.map(operation)
}

val numbers = listOf(1, 2, 3, 4, 5)
val doubledNumbers = numbers.applyOperation { it * 2 }
println(doubledNumbers)  // [2, 4, 6, 8, 10]

このコードでは、ジェネリックなリストに対する拡張関数applyOperationを定義しています。

この関数は、リストの各要素に対して適用する関数を引数operationとして受け取ります。

また、引数operationにはデフォルトの関数として、要素をそのまま返す関数が設定されています。

コードを実行すると、applyOperation関数を呼び出す際に指定したラムダ式{ it * 2 }が各要素に適用され、その結果として2倍になった数値が新たなリストとして生成されます。

●注意点と対処法

Kotlinでデフォルト引数を使用する際、一見シンプルで強力に思えるこの機能にも幾つかの注意点が存在します。

これらを理解することで、より安全かつ効率的にコーディングを進めることができます。

○オーバーロードとの競合

デフォルト引数を持つ関数やメソッドと、その引数を持たない同名の関数やメソッドをオーバーロードして定義することは、コンパイルエラーの原因となります。

fun showMessage(message: String = "Hello") {
    println(message)
}

// 以下の関数はコンパイルエラーとなる
// fun showMessage() {
//     println("Hi")
// }

このコードのコメント部分を外すと、コンパイルエラーが発生します。

なぜなら、デフォルト引数を持つ関数とその引数を持たない同名の関数が競合するからです。

このような場合、オーバーロードせずに、デフォルト引数を適切に利用することで競合を回避する必要があります。

○Javaとの互換性

KotlinはJavaとの相互運用性を持っていますが、JavaからKotlinのデフォルト引数を持つ関数を呼び出す際には、デフォルト引数を適用することができません。

このため、Javaから呼び出す予定の関数には、デフォルト引数を避けるか、必要に応じてオーバーロードすることが推奨されます。

○可読性の低下

デフォルト引数の乱用は、コードの可読性を低下させる可能性があります。

特に多数のデフォルト引数を持つ関数は、呼び出し元でどの引数が指定されているのか一見判断しにくくなる場合があります。

デフォルト引数は必要最低限に留め、適切な命名やコメントを用いてコードの可読性を確保することが重要です。

●カスタマイズ方法

Kotlinのデフォルト引数は、関数の使い勝手を向上させるための強力な機能の一つです。

しかしながら、場面や要件によっては、このデフォルト引数を更にカスタマイズして利用することが望ましい場合もあります。

ここでは、デフォルト引数のカスタマイズの方法とその具体例を取り上げます。

○条件によるデフォルト引数の変更

デフォルト引数は、静的な値だけでなく、関数内部のロジックに基づいて動的に決定することも可能です。

fun greeting(time: Int = System.currentTimeMillis()): String {
    return if (time < 12) "おはようございます" else "こんにちは"
}

// 呼び出し例
val morningMessage = greeting(10)
val defaultMessage = greeting()

このコードでは、現在の時間に基づいて挨拶のメッセージを変える関数を定義しています。

引数が指定されない場合は、現在のシステム時間を基にデフォルト引数が設定され、適切な挨拶を返します。

○デフォルト引数と拡張関数の組み合わせ

Kotlinでは拡張関数を利用して、既存のクラスやインターフェースに新しい関数を追加することができます。

この機能とデフォルト引数を組み合わせることで、より柔軟なAPIの設計が可能となります。

fun String.appendExclamation(times: Int = 1): String {
    return this + "!".repeat(times)
}

// 呼び出し例
val emphasized = "Hello".appendExclamation(3) // "Hello!!!"
val normal = "Hello".appendExclamation() // "Hello!"

このコードでは、文字列に感嘆符を追加する拡張関数を定義しています。

デフォルト引数を利用して、感嘆符の回数を指定することができます。

まとめ

Kotlinのデフォルト引数は、関数やメソッドの呼び出しをより柔軟にし、コードの読みやすさやメンテナンス性を高めるための重要な機能です。

この記事を通じて、デフォルト引数の基本的な使い方から応用、さらにはカスタマイズ方法まで幅広く学ぶことができたかと思います。

Kotlinのデフォルト引数は非常に強力な機能である一方で、過度な利用はコードの複雑性を高める原因となる場合もあるため、バランス良く利用することが肝心です。

適切な場面でデフォルト引数を活用し、よりクリーンで効率的なKotlinのコードを書くための基盤を築いてください。