コトリンのラムダ式
1概要
この記事では、ラムダをKotlin言語で探求します。
ラムダはKotlin独自のものではなく、他の多くの言語で長年使用されてきました。
-
ラムダ式は本質的に値として扱うことができる無名関数です – ** たとえば、それらをメソッドへの引数として渡したり、それらを返したり、あるいは通常のオブジェクトを使ってできることができます。
2ラムダ
の定義
ご覧のとおり、Kotlin LambdasはJava Lambdasと非常によく似ています。 Java Lambdasの使い方やベストプラクティスのリンクについての詳細は、/java-8-lambda-expressions-tips[ここ]を参照してください。
ラムダを定義するには、構文に固執する必要があります。
val lambdaName : Type = { argumentList -> codeBody }
-
オプションではないラムダの唯一の部分は
codeBodyです。**
最大1つの引数を定義するときに引数リストをスキップすることができ、
__Type
__はKotlinコンパイラによって推測されることがよくあります。
変数も必ずしも必要ではありません。ラムダはメソッドの引数として直接渡すことができます。
ラムダブロック内の最後のコマンドの型は返される型です。
2.1. 型推論
Kotlinの型推論は、ラムダの型がコンパイラによって評価されることを可能にします。
数の2乗を生成するラムダを書くのは、次のように書くことになります。
val square = { number: Int -> number ** number }
val nine = square(3)
Kotlinは上記の例を1つの
_Int
を取り、
Intを返す関数であると評価します。
(Int) – > Int_
単一の引数の数に100を掛けたラムダを作成したい場合は、その値を__Stringとして返します。
val magnitude100String = { input : Int ->
val magnitude = input ** 100
magnitude.toString()
}
Kotlinはこのラムダが
(Int) – > String
型であることを理解するでしょう。
2.2. 型宣言
時折、Kotlinは私たちの型を推測できず、ラムダの型を明示的に宣言しなければなりません。他の型と同じようにできます。
パターンは
input – > output
ですが、コードが値を返さない場合は
Unit
型を使用します。
val that : Int -> Int = { three -> three }
val more : (String, Int) -> String = { str, int -> str + int }
val noReturn : Int -> Unit = { num -> println(num) }
-
クラス拡張としてラムダを使うことができます。
val another : String.(Int) -> String = { this + it }
ここで使用するパターンは、定義した他のラムダとは少し異なります。括弧にはまだ引数が含まれていますが、括弧の前には、このラムダを添付するタイプがあります。
このパターンを
__Stringから使用するには、
Type.lambdaName(arguments)
__を呼び出して、別の例を呼び出します。
fun extendString(arg: String, num: Int) : String {
val another : String.(Int) -> String = { this + it }
return arg.another(num)
}
2.3. ラムダから戻る
最後の式は、ラムダが実行された後に返される値です。
val calculateGrade = { grade : Int ->
when(grade) {
in 0..40 -> "Fail"
in 41..70 -> "Pass"
in 71..100 -> "Distinction"
else -> false
}
}
最後の方法は、無名関数の定義を利用することです。引数と戻り型を明示的に定義する必要があり、他のメソッドと同じようにreturnステートメントを使用することができます。
val calculateGrade = fun(grade: Int): String {
if (grade < 0 || grade > 100) {
return "Error"
} else if (grade < 40) {
return "Fail"
} else if (grade < 70) {
return "Pass"
}
return "Distinction"
}
3
それ
単一引数のラムダの省略形は、キーワード「__it」を使用することです。 ** この値は、lambda関数に渡す引数のうちの唯一の引数を表します。
以下の
Ints
の配列に対しても、同じ
__forEach
__メソッドを実行します。
val array = arrayOf(1, 2, 3, 4, 5, 6)
最初に、ラムダ関数の簡略形式を見て、次に同じコードの簡略形式を見ていきます。ここで、 ‘
it
‘は次の配列の各要素を表します。
速記:
array.forEach { item -> println(item ** 4) }
速記:
array.forEach { println(it ** 4) }
** 4ラムダの実装
**
スコープ内にあるラムダを呼び出す方法と、引数としてラムダを渡す方法について、簡単に説明します。
ラムダオブジェクトがスコープ内に入ったら、その名前の後にかっこと引数を続けて、他のスコープ内メソッドとして呼び出します。
fun invokeLambda(lambda: (Double) -> Boolean) : Boolean {
return lambda(4.329)
}
高階メソッドに引数としてラムダを渡す必要がある場合、5つの選択肢があります。
4.1. ラムダオブジェクト変数
セクション2で宣言されているように既存のラムダオブジェクトを使用して、他の引数と同じようにオブジェクトをメソッドに渡します。
@Test
fun whenPassingALambdaObject__thenCallTriggerLambda() {
val lambda = { arg: Double ->
arg == 4.329
}
val result = invokeLambda(lambda)
assertTrue(result)
}
4.2. ラムダリテラル
ラムダを変数に代入する代わりに、リテラルを直接メソッド呼び出しに渡すことができます。
Test
fun whenPassingALambdaLiteral__thenCallTriggerLambda() {
val result = invokeLambda({
true
})
assertTrue(result)
}
4.3. 括弧の外側のラムダリテラル
JetBrainsによって推奨されているラムダリテラルのもう一つのパターンは – メソッドへの最後の引数としてラムダを渡し、メソッド呼び出しの外側にラムダを置くことです:
@Test
fun whenPassingALambdaLiteralOutsideBrackets__thenCallTriggerLambda() {
val result = invokeLambda { arg -> arg.isNaN() }
assertFalse(result)
}
4.4. メソッド参照
最後に、メソッド参照を使用するという選択肢があります。これらは既存のメソッドへの参照です。
- 以下の例では、__Double
-
isFinite
を取ります。その関数はラムダと同じ構造を取りますが、
KFunction1 <Double、Boolean>型で、引数が1つあるので
Double
を取り、
Boolean__を返します。
@Test
fun whenPassingAFunctionReference__thenCallTriggerLambda() {
val reference = Double::isFinite
val result = invokeLambda(reference)
assertTrue(result)
}
5. JavaのKotlin Lambda
Kotlinは生成された関数インターフェースを使ってJavaと相互運用します。それらはKotlinのソースコードhttps://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/jvm/runtime/kotlin/jvm/functions/Functions.kt[ここ]に存在します。
これらの生成されたクラスで渡すことができる引数の数には制限があります。電流制限は22です。インタフェース
Function22
で表されます。
__Function
__インタフェースの総称の構造は、その数がラムダへの引数の数を表し、その数のクラスが順番に引数の型になるということです。
最後の総称引数は戻り型です。
import kotlin.jvm.functions.**
public interface Function1<in P1, out R> : Function<R> {
public operator fun invoke(p1: P1): R
}
-
Kotlinコード内に戻り型が定義されていない場合、ラムダはKotlin
Unit
を返します。
** Javaコードは
__kotlin
packageからクラスをインポートし、
null__を返す必要があります。
以下は、KotlinおよびJavaの一部であるプロジェクトからKotlin Lambdaを呼び出す例です。
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
...
new Function1<Customer, Unit>() {
@Override
public Unit invoke(Customer c) {
AnalyticsManager.trackFacebookLogin(c.getCreated());
return null;
}
}
Java8を使うとき、
__ Function
__anonymousクラスの代わりにJavaラムダを使います。
@Test
void givenJava8__whenUsingLambda__thenReturnLambdaResult() {
assertTrue(LambdaKt.takeLambda(c -> c >= 0));
}
6.匿名の内部クラス
Kotlinには、匿名内部クラスを扱うための2つの興味深い方法があります。
6.1. オブジェクト式
Kotlinの内部匿名クラスまたは複数のメソッドで構成されるJava匿名クラスを呼び出すときには、オブジェクト式を実装する必要があります。
これを実証するために、単純なインターフェースとそのインターフェースの実装を受け取り、
__ Boolean
__引数に依存するメソッドを呼び出すクラスを取ります。
class Processor {
interface ActionCallback {
fun success() : String
fun failure() : String
}
fun performEvent(decision: Boolean, callback : ActionCallback) : String {
return if(decision) {
callback.success()
} else {
callback.failure()
}
}
}
匿名の内部クラスを提供するために、「オブジェクト」構文を使う必要があります。
@Test
fun givenMultipleMethods__whenCallingAnonymousFunction__thenTriggerSuccess() {
val result = Processor().performEvent(true, object : Processor.ActionCallback {
override fun success() = "Success"
override fun failure() = "Failure"
})
assertEquals("Success", result)
}
6.2. ラムダ式
一方、代わりにラムダを使用するという選択肢もあります。匿名内部クラスの代わりにラムダを使用することには一定の条件があります。
-
このクラスはJavaインターフェースの実装です(Kotlinのインターフェースではありません).
-
インターフェースは最大値を持つ必要があります
これらの条件の両方が満たされるならば、代わりにラムダ式を使うかもしれません。
ラムダ自体は、インタフェースの単一メソッドと同じ数の引数を取ります。
一般的な例は、標準のJava __Consumerの代わりにラムダを使用することです。
……
val list = ArrayList <Int>(2)
list.stream()
.forEach({i – > println(i)})
……
7.
まとめ
構文的には似ていますが、KotlinとJavaのラムダはまったく異なる機能です。 Java 6をターゲットにするとき、KotlinはそのラムダをJVM 1.6内で利用できる構造に変換しなければなりません。
それにもかかわらず、Java 8ラムダのベストプラクティスは依然として適用されます。
ラムダのベストプラクティスについてのリンクはこちら:/java-8-lambda-expressions-tips[ここ]。
いつものように、コードスニペットはhttps://github.com/eugenp/tutorials/tree/master/core-kotlin[GitHubに追加]を見つけることができます。