Kotlin言語の紹介

1概要

このチュートリアルでは、JVMの世界で新しい言語となっているKotlinと、クラス、継承、条件付きステートメント、ループ構造などの基本機能について説明します。

それから、Kotlinを魅力的な言語にする主な機能のいくつかを見ていきます。それには、null安全性、データクラス、拡張関数、そして String テンプレートが含まれます。

2 Mavenの依存関係

MavenプロジェクトでKotlinを使用するには、Kotlin標準ライブラリを pom.xml に追加する必要があります。

<dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-stdlib</artifactId>
    <version>1.0.4</version>
</dependency>

KotlinのJUnitサポートを追加するには、以下の依存関係も含める必要があります。

<dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-test-junit</artifactId>
    <version>1.0.4</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

https://search.maven.org/classic/#search%7C1%7Cg%3A%22org.jetbrains.kotlin%22%20AND%20a%3A%22kotlin-stdlib%22 の最新バージョンを見つけることができます。 kotlin-stdlib [Maven Centralの[kotlin-test-junit]、およびhttps://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22junit%22%20AND%20a%3A%22junit%22[junit]。

最後に、Mavenビルドを実行するためにソースディレクトリとKotlinプラグインを設定する必要があります。

<build>
    <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
    <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
    <plugins>
        <plugin>
            <artifactId>kotlin-maven-plugin</artifactId>
            <groupId>org.jetbrains.kotlin</groupId>
            <version>1.0.4</version>
            <executions>
                <execution>
                    <id>compile</id>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
                <execution>
                    <id>test-compile</id>
                    <goals>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

あなたはhttps://search.maven.org/classic/#search%7C1%7Cg%3A%22org.jetbrains.kotlin%22%20AND%20a%3A%22kotlin-maven-plugin%の最新バージョンを見つけることができます。 Maven Centralの22[kotlin-maven-plugin]。

3.基本的な構文

Kotlin言語の基本的な構成要素を見てみましょう。

Javaと多少の類似点があります(例:パッケージの定義も同じです)違いを見てみましょう。

3.1. 関数を定義する

Int 戻り型の2つのIntパラメータを持つ関数を定義しましょう。

fun sum(a: Int, b: Int): Int {
    return a + b
}

3.2. ローカル変数の定義

代入1回(読み取り専用)ローカル変数

val a: Int = 1
val b = 1
val c: Int
c = 1

変数 b の型はKotlinコンパイラによって推論されることに注意してください。可変変数を定義することもできます。

var x = 5
x += 1

4.オプションのフィールド

Kotlinには、null入力可能なフィールドを定義するための基本的な構文があります(オプション)。フィールドの型がNULL可能であることを宣言したい場合は、疑問符を付けた型を使用する必要があります。

val email: String?

NULL可能フィールドを定義したとき、それに null を代入することは完全に有効です。

val email: String? = null

つまり、Eメールフィールドには__nullが含まれる可能性があります。

val email: String = "value"

それから私達は私達が電子メールを宣言するのと同じステートメントで電子メールフィールドに値を割り当てる必要があります。 null値を持つことはできません。 Kotlinの安全性については後のセクションで取り上げます。

5クラス

商品の特定のカテゴリを管理するための単純なクラスを作成する方法を説明しましょう。以下の ItemManager クラスには、 categoryId dbConnection の2つのフィールドとオプションの email フィールドを設定するデフォルトのコンストラクタがあります。

class ItemManager(val categoryId: String, val dbConnection: String) {
    var email = ""
   //...
}

その ItemManager(…​) コンストラクトは、コンストラクターとクラス内に2つのフィールド( categoryId および dbConnection )を作成します。

私たちのコンストラクタはその引数に val キーワードを使うことに注意してください - これは対応するフィールドが final で不変であることを意味します。

var キーワードを使用した場合( email フィールドを定義したときのように)、それらのフィールドは可変になります。

デフォルトのコンストラクタを使用してItemManagerのインスタンスを作成しましょう。

ItemManager("cat__id", "db://connection")

名前付きパラメータを使用して ItemManager を構築できます。この例のように同じ型の2つのパラメータを取る関数が好きなときにとても便利です。あなたはそれらの順序を混同したくありません。命名パラメータを使用して、どのパラメータが割り当てられるかを明示的に書くことができます。 ItemManager クラスには categoryId dbConnection の2つのフィールドがあるため、両方とも名前付きパラメータを使用して参照できます。

ItemManager(categoryId = "catId", dbConnection = "db://Connection")

関数にもっと多くの引数を渡す必要があるときにとても便利です。

追加のコンストラクタが必要な場合は、 constructor キーワードを使用してそれらを定義します。 email フィールドも設定する別のコンストラクタを定義しましょう。

constructor(categoryId: String, dbConnection: String, email: String)
  : this(categoryId, dbConnection) {
    this.email = email
}

このコンストラクタは、emailフィールドを設定する前に、上で定義したデフォルトのコンストラクタを呼び出します。また、デフォルトコンストラクタの val キーワードを使用して categoryId dbConnection を不変にするようにすでに定義しているので、追加のコンストラクタで val キーワードを繰り返す必要はありません。

それでは、追加のコンストラクタを使用してインスタンスを作成しましょう。

ItemManager("cat__id", "db://connection", "[email protected]")

ItemManager でインスタンスメソッドを定義したい場合は、 fun キーワードを使用して定義します。

fun isFromSpecificCategory(catId: String): Boolean {
    return categoryId == catId
}

6. 継承

デフォルトでは、Kotlinのクラスは拡張のために閉じられています - これはJavaで final とマークされたクラスと同等です。

クラスが拡張用に開かれていることを指定するには、クラスを定義するときに open キーワードを使用します。

拡張可能な Item クラスを定義しましょう。

open class Item(val id: String, val name: String = "unknown__name") {
    open fun getIdOfItem(): String {
        return id
    }
}

getIdOfItem() メソッドもopenと表記しています。これにより、上書きすることができます。

それでは、 Item クラスを拡張し、 getIdOfItem() メソッドをオーバーライドしましょう。

class ItemWithCategory(id: String, name: String, val categoryId: String) : Item(id, name) {
    override fun getIdOfItem(): String {
        return id + name
    }
}

7. 条件付きステートメント

Kotlinでは、条件付きステートメント if は何らかの値を返す関数と同等です。例を見てみましょう。

fun makeAnalyisOfCategory(catId: String): Unit {
    val result = if (catId == "100") "Yes" else "No"
    println(result)
}

この例では、 catId が“ 100”に等しい場合、条件ブロックは“ Yes”を返し、そうでなければ“ No”を返します。

通常の if else ブロックを作成できます。

val number = 2
if (number < 10) {
    println("number less that 10")
} else if (number > 10) {
    println("number is greater that 10")
}

Kotlinには非常に便利な when コマンドがあり、これは高度なswitch文のように動作します。

val name = "John"
when (name) {
    "John" -> println("Hi man")
    "Alice" -> println("Hi lady")
}

8.コレクション

Kotlinには2種類のコレクションがあります。それは可変と不変です。

不変コレクションを作成すると、それは読み取り専用です。

val items = listOf(1, 2, 3, 4)

そのリストにはadd function要素はありません。

変更可能な可変リストを作成したい場合は、 mutableListOf() メソッドを使用する必要があります。

val rwList = mutableListOf(1, 2, 3)
rwList.add(5)

可変リストには add() メソッドがあるので、それに要素を追加することができます。

他の種類のコレクションと同等の方法もあります。

mutableMapOf()、mapOf()、setOf()、mutableSetOf()

9.例外

例外処理のメカニズムは、Javaのメカニズムと非常によく似ています。

すべての例外クラスは__Throwableを継承しています。例外にはメッセージ、スタックトレース、およびオプションの原因が必要です。 Kotlinのすべての例外はチェックされていません 、これはコンパイラがそれらをキャッチすることを強制していないことを意味します。

例外オブジェクトをスローするには、throw式を使用する必要があります。

throw Exception("msg")

例外の処理は try …​ catchブロックを使用して行われます(finally オプション)。

try {

}
catch (e: SomeException) {

}
finally {

}

10.ラムダ

Kotlinでは、ラムダ関数を定義し、それらを他の関数への引数として渡すことができます。

単純なラムダを定義する方法を見てみましょう。

val sumLambda = { a: Int, b: Int -> a + b }

引数として Int 型の2つの引数を取り、 Int. を返す sumLambda 関数を定義しました。

ラムダを渡すことができます:

@Test
fun givenListOfNumber__whenDoingOperationsUsingLambda__shouldReturnProperResult() {
   //given
    val listOfNumbers = listOf(1, 2, 3)

   //when
    val sum = listOfNumbers.reduce { a, b -> a + b }

   //then
    assertEquals(6, sum)
}

** 11ループ構成

Kotlinでは、コレクションのループは標準の for..in 構文を使って行うことができます。

val numbers = arrayOf("first", "second", "third", "fourth")
for (n in numbers) {
    println(n)
}

整数の範囲にわたって反復したい場合は、範囲構成を使用できます。

for (i in 2..9 step 2) {
    println(i)
}

上記の例の範囲は両側を含むことに注意してください。 step パラメータはオプションであり、各反復でカウンタを2回インクリメントするのと同じです。出力は以下のようになります。

2
4
6
8

次のように Int クラスで定義されている rangeTo() 関数を使用できます。

1.rangeTo(10).map{ it **  2 }

結果には以下が含まれます( rangeTo() も包括的です)。

----[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]----

12. ヌル安全性

Kotlinの重要な機能の1つである、安全性の無効化を言語に組み込みます。なぜこれが便利なのかを説明するために、 Item オブジェクトを返す単純なサービスを作成します。

class ItemService {
    fun findItemNameForId(id: String): Item? {
        val itemId = UUID.randomUUID().toString()
        return Item(itemId, "name-$itemId");
    }
}

注意すべき重要なことは、そのメソッドの戻り型です。疑問符が続くオブジェクトです。これはKotlin言語からの構成体です。つまり、そのメソッドから返される Item はnullになる可能性があります。

私たちはコンパイル時にそのケースを処理する必要があり、そのオブジェクトに対して何をしたいのかを決定します(それはJava 8の Optional <T> 型とほぼ同等です)。

メソッドシグネチャに疑問符のないタイプがある場合:

fun findItemNameForId(id: String): Item

それがコンパイラとKotlin言語によって保証されているので、コードを呼び出すことはnullケースを扱う必要はないでしょう、その返されたオブジェクトはnullであることができません。

それ以外の場合、** メソッドに渡されるnull許容オブジェクトがあり、その場合が処理されないと、コンパイルされません。

Kotlin型安全のテストケースを書きましょう。

val id = "item__id"
val itemService = ItemService()

val result = itemService.findItemNameForId(id)

assertNotNull(result?.let { it -> it.id })
assertNotNull(result!!.id)

ここでは、メソッド findItemNameForId()を実行した後の 返される型はKotlin Nullable です。そのオブジェクトのフィールド( id )にアクセスするには、コンパイル時にそのケースを処理する必要があります。メソッド let() は、結果がNULL不可の場合にのみ実行されます。 Id フィールドはnullセーフなので、ラムダ関数内でアクセスできます。

null入力可能オブジェクトフィールドにアクセスするもう1つの方法は、Kotlin演算子__ !!を使用することです。

if (result == null){
    throwNpe();
}
return result;

Kotlinはそのオブジェクトが null であるかどうかを調べます。もしそうであれば__NullPointerExceptionを投げます。

関数 throwNpe() はKotlinの内部関数です。

13. データクラス

Kotlinで見つけることができるとても良い言語構成はデータクラスです(それはScala言語からの「case class」と同等です)。そのようなクラスの目的はデータを保持することだけです。この例では、データのみを保持する Item クラスがあります。

data class Item(val id: String, val name: String)

コンパイラは、メソッド hashCode() equals() 、および toString() を作成します。 val キーワードを使用して、データクラスを不変にすることをお勧めします。データクラスはデフォルトのフィールド値を持つことができます:

data class Item(val id: String, val name: String = "unknown__name")

name フィールドにはデフォルト値 "unknown name" .__があることがわかります。

14. 拡張機能

サードパーティライブラリの一部であるクラスがあるとしますが、追加のメソッドでそれを拡張したいと思います。 Kotlinでは、これを拡張関数を使って行うことができます。

要素のリストがあり、そのリストからランダムな要素を取り出したいという例を考えてみましょう。サードパーティの List クラスに新しい関数 random() を追加します。

これがKotlinの様子です。

fun <T> List<T>.random(): T? {
    if (this.isEmpty()) return null
    return get(ThreadLocalRandom.current().nextInt(count()))
}

ここで注意すべき最も重要なことはメソッドのシグネチャです。

このメソッドには、この追加のメソッドを追加するクラスの名前がプレフィックスとして付けられます。

拡張メソッドの内部では、リストのスコープを操作します。したがって、 this を使用すると、 isEmpty() や__count()のようなリストインスタンスメソッドへのアクセスが許可されます。その範囲内です:

fun <T> getRandomElementOfList(list: List<T>): T? {
    return list.random()
}

リストを受け取り、それから以前に定義されたカスタム拡張関数 random() を実行するメソッドを作成しました。新しい機能のテストケースを書きましょう。

val elements = listOf("a", "b", "c")

val result = ListExtension().getRandomElementOfList(elements)

assertTrue(elements.contains(result))

サードパーティのクラスを「拡張する」関数を定義することは非常に強力な機能であり、コードをより簡潔で読みやすくすることができます。

15. 文字列テンプレート

Kotlin言語の非常に優れた機能は __String s用のテンプレートを使用する可能性です。手動で String __sを連結する必要がないのでとても便利です。

val firstName = "Tom"
val secondName = "Mary"
val concatOfNames = "$firstName + $secondName"
val sum = "four: ${2 + 2}"

$ \ {} ブロック内の式を評価することもできます。

val itemManager = ItemManager("cat__id", "db://connection")
val result = "function result: ${itemManager.isFromSpecificCategory("1")}"

16. KotlinとJavaの相互運用性

Kotlin - Javaの相互運用性はシームレスに簡単です。 __Stringを操作するメソッドを持つJavaクラスがあるとしましょう。

class StringUtils{
    public static String toUpperCase(String name) {
        return name.toUpperCase();
    }
}

今度はKotlinクラスからそのコードを実行したいのです。そのクラスをインポートするだけでよく、KotlinからJavaメソッドを問題なく実行できます。

val name = "tom"

val res = StringUtils.toUpperCase(name)

assertEquals(res, "TOM")

見てのとおり、KotlinコードのJavaメソッドを使いました。

JavaからKotlinコードを呼び出すのもとても簡単です。簡単なKotlin関数を定義しましょう。

class MathematicsOperations {
    fun addTwoNumbers(a: Int, b: Int): Int {
        return a + b
    }
}

Javaコードから addTwoNumbers() を実行するのはとても簡単です。

int res = new MathematicsOperations().addTwoNumbers(2, 4);

assertEquals(6, res);

Kotlinコードへの呼び出しは私たちには見えないことがわかります。

戻り型が void であるメソッドをjavaで定義すると、Kotlinでは戻り値は Unit 型になります。

Java言語には、Kotlinコードで使用するときにエスケープする必要がある特殊な識別子( is object in 、..)があります。たとえば、 object() という名前のメソッドを定義できますが、これはjavaでは特別な識別子であるため、その名前をエスケープすることを忘れないでください。

fun `object`(): String {
    return "this is object"
}

それからそのメソッドを実行することができます:

`object`()

17. 結論

この記事ではKotlin言語とその主要機能について紹介します。それは、ループ、条件付きステートメント、そしてクラスの定義のような単純な概念を導入することから始まります。それから、拡張機能とnull安全のようないくつかのより高度な機能を示します。

これらすべての例とコードスニペットの実装はhttps://github.com/eugenp/tutorials/tree/master/core-kotlin[GitHubプロジェクト]にあります - これはMavenプロジェクトなので、簡単にできます。そのままインポートして実行します。