1️⃣

Kotlinを触ってみた #1

2023/06/28に公開

はじめに

Kotlinの名前は聞いたことがありますが実際にどのような言語かわからなかったので

KotlinについてのサイトやChat GPTを参考に学んだことなどを書いていきたいと思います。

練習環境はWebで簡単にKotlinの練習ができるサイトを見つけたのでそちらを利用しながら

Kotlinについて学びました。

(↓こちらのサイトで実行しながら勉強しました。)

https://play.kotlinlang.org/#eyJ2ZXJzaW9uIjoiMS44LjIxIiwicGxhdGZvcm0iOiJqYXZhIiwiYXJncyI6IiIsIm5vbmVNYXJrZXJzIjp0cnVlLCJ0aGVtZSI6ImlkZWEiLCJjb2RlIjoiZnVuIG1haW4oICkge1xuICBwcmludGxuKFwiSGVsbG8sIHdvcmxkIVwiKVxufSJ9

Kotlin(コトリン)とは?

Kotlinは、Javaプログラミング言語に代わるオブジェクト指向のプログラミング言語です。

Kotlinは構文がシンプルで読みやすく、安全性、表現力、効率性を重視しています。

Kotlinの特徴がいくつかあります。

  1. シンプルな構文 : Kotlinはシンプルな構文を持っており、Javaと比べて冗長なコードを少なくすることができます。

  2. オプショナルな変数宣言 : Kotlinでは、変数やプロパティの宣言時に明示的に型を指定する必要がありません。コンパイラが型を推論してくれます。これにより、初心者の方でも変数宣言が簡単に行えます。

  3. Null安全性 : Kotlinでは、nullポインターエラーを避けるためのnull安全性が組み込まれています。変数やプロパティがnullを許容する場合は明示的に型に?を付ける必要があり、nullチェックを行うことが推奨されます。これにより、実行時のエラーを事前に防ぐことができます。

  4. 拡張関数: Kotlinでは、既存のクラスに対して拡張関数を定義することができます。これにより、既存のクラスに独自の機能を追加することができます。たとえば、文字列型に対して独自のメソッドを追加することができます。

  5. Android開発のサポート: KotlinはAndroid開発においても公式にサポートされています。これは、Android StudioやAndroid SDKとの統合がスムーズであり、最新のAndroidフレームワークとの互換性が保たれていることを意味しています。

これらの特徴により、Kotlinは初心者の方にも分かりやすい言語となっています。また、既存のJavaコードとの相互運用性も高いため、Javaの知識を活かしながらKotlinに移行することも容易です。

Hello World

fun main() {
    println("Hello, World!")
}

Javaとのコードの違い

  • Kotlinではmainメソッド(操作や機能を実行するためのコードのまとまり)のためにわざわざクラスを作る必要がない。
  • kotlinのprintlnはメソッドではなくクラスに属さない関数として実装されている為System.outを書かなくても良い
  • 関数はstaticメソッドのようなもの つまりstaticは書く必要はない。
  • 文末の ; はいらない。

変数宣言 (JavaとKotlinの比較)

// Javaの場合
String s = "abc";
final String t = "xyz";
----------------------------------------------------------------------------
// Kotlinの場合
var s: String = "abc"
val t: String = "xyz"
  • kotlinは変数の後ろに型がつく
  • final(宣言後変更不可)な変数宣言val

変更可能な変数宣言はvar

  • 変数を宣言する際にできるだけ不変性を保ち、変更が不要な場合にはvalを使用し、変更が必要な場合にのみvarを使用する。

Kotlin では 型推論( Type Inference ) によって変数宣言時に型を省略することができるため、Javaよりも簡単に書けます。

//型推論( Type Inference )によって型を省略
var s = "abc"
val t = "xyz"

プリミティブ型

プリミティブ型 : プログラミング言語において基本的なデータ型として提供される型のこと

  1. 整数型
    • Byte: 8ビット符号付き整数
    • Short: 16ビット符号付き整数
    • Int: 32ビット符号付き整数
    • Long: 64ビット符号付き整数
  2. 浮動小数点数型
    • Float: 32ビット浮動小数点数
    • Double: 64ビット浮動小数点数
  3. 文字型
    • Char: 16ビットUnicode文字
  4. 真偽値型
    • Boolean: 真偽値 (trueまたはfalse)

Kotlin では Java でいうプリミティブ型の型名も IntDoubleBoolean(真偽) のように大文字で始めます。

fun main() {
    // 整数型
    val byteValue: Byte = 10
    val shortValue: Short = 100
    val intValue: Int = 1000
    val longValue: Long = 1000000L // Lサフィックスで長整数を示す

    // 浮動小数点数型
    val floatValue: Float = 3.14F // Fサフィックスで単精度浮動小数点数を示す
    val doubleValue: Double = 3.14159

    // 文字型
    val charValue: Char = 'A'

    // 真偽値型
    val booleanValue: Boolean = true

    println(byteValue)
    println(shortValue)
    println(intValue)
    println(longValue)
    println(floatValue)
    println(doubleValue)
    println(charValue)
    println(booleanValue)
}
実行結果
10
100
1000
1000000

3.14
3.14159

A

true

Javaでは、プリミティブ型(int、double、booleanなど)とそれに対応するラッパークラス(Integer、Double、Booleanなど)があります。プリミティブ型は値そのものを表し、ラッパークラスはプリミティブ型をオブジェクトとして扱うためのクラスです。

一方、Kotlinでは、データ型におけるプリミティブ型とラッパークラスの区別はありません。Kotlinのデータ型はすべてクラスとして振る舞い、メソッドを呼び出すことができます。

Kotlinのデータ型には特別な性質があります。

例えば、KotlinのInt型はプリミティブ型のintと同等の性能を持ちます。

つまり、Int型の変数に対してメソッドを呼び出すことは、Javaのint型の変数をstaticメソッドに渡すのと同じようなものです。

なぜなら、Kotlinのコンパイラは必要に応じてプリミティブ型としての最適化を行い、自動的にボクシングやアンボクシングを行います。これにより、Kotlinのデータ型はプリミティブ型と同じようなパフォーマンスを提供します。

ただし、Kotlinのジェネリック型(例:List<Int>)にはプリミティブ型のボクシングが適用されます。

つまり、List<Int>内の要素はボクシングされたオブジェクトとして保持されます。これにより、一部のパフォーマンスの低下が発生する可能性があります。

簡単に言えば、Kotlinではデータ型を選ぶ際にプリミティブ型とラッパークラスの違いを意識する必要はありません。Kotlinのデータ型はオブジェクト指向の特徴を持ちながらも、パフォーマンスの面ではプリミティブ型と同等の効率を提供します。

制御構文

if文

基本的に Java と同じです。

しかし、 Kotlin の if はとして使えるので、次のように if や else ブロックの中で最後に評価された式の値を直接代入することができます。

// Javaの場合
final String foo;
if (bar < 42) {
  foo = "abc";
} else {
  foo = "xyz";
}

----------------------------------------------------------------------------
// Kotlinの場合
val foo = if (bar < 42) {
  "abc"
} else {
  "xyz"
}

if が式として使えることから

条件式 ? 真の場合の値 : 偽の場合

のようなJava の三項演算子 は

Kotlin にはありません。if で三項演算子を表せることができます。

// Javaの場合
final String foo = bar < 42 ? "abc" : "xyz";
----------------------------------------------------------------------------
// Kotlinの場合
val foo = if (bar < 42) "abc" else "xyz"

While文

ほぼjavaと同じ

//Javaの場合
public class Main {
    public static void main(String[] args) {
        int count = 0;

        while (count < 5) {
            System.out.println("Count: " + count);
            count++;
        }
    }
}
----------------------------------------------------------------------------
//Kotolinの場合
fun main() {
    var count = 0

    while (count < 5) {
        println("Count: $count")
        count++
    }
}

For文

構文はほぼ同じだが、 : のかわりにinを使います

//Javaの場合
public class a {
    public static void main(String[] args) {
        int[] numbers = { 1, 2, 3, 4, 5 };

        for (int number : numbers) {
            System.out.println(number);
        }

    }
}
----------------------------------------------------------------------------
// Kotlinの場合
fun main() {
    val numbers = intArrayOf(1, 2, 3, 4, 5)

    for (number in numbers) {
        println(number)
    }
}

↓ のようなパターンでは次のように書きます。

// Javaの場合
for (int i = 0; i< 100; i++) {
  System.out.println(i);
}
----------------------------------------------------------------------------
// Kotlinの場合
for (i in 0 until 100) {
  println(i)
}

Kotlinのuntilは特殊な構文ではなく、実際にはuntilというメソッドです。

0.until(100)は単に0という整数から始まり、100より小さい整数までの範囲を表します。

Kotlinでは、演算子(+*)と同様の中置記法のメソッドを作成できます。

つまり、0 until 1000.until(100)と同じです。

0 until 100の戻り値はIntRangeという範囲を表す特殊な型です。そして、IntRangeIterableインターフェースを実装しているため、for-inループを使って範囲内の値を順番に反復処理することができます。

要するに、0 until 100は「0から始まり、100未満の整数の範囲」を表すという意味です。

この範囲内の値をfor-inループで簡単に取得できます。

このほかにも様々なメソッドを使ってループ表現ができます。

// Kotlin
for (i in 99 downTo 0) println(i) 99から0まで1つずつ下がる // for (int i = 99; i >= 0; i--)
for (i in 0 until 100 step 2) println(i) 0から2ずつ上がっていく // for (int i = 0; i < 100; i += 2)
for (i in 1..100) println(i) //1から100まで for (int i = 1; i <= 100; i++)

switch → when

switch 文は  Kotlin では when になります。

when も式として使えるので、次のように簡単に書けます。

また、 switch と違って次の case に進むことはないので break を忘れる心配もありません。

// Javaの場合
public class main {
    public static void main(String[] args) {
        int number = 1;

        switch (number) {
            case 1:
                System.out.println("The number is 1");
                break;
            case 2:
            case 3:
                System.out.println("The number is 2 or 3");
                break;
            case 4:
            case 5:
            case 6:
                System.out.println("The number is between 4 and 6");
                break;
            default:
                System.out.println("The number is not matched");
                break;
        }
    }
}
-------------------------------------------------------------------------------
// Kotlinの場合
fun main() {
    val number = 1

    when (number) {
        1 -> println("The number is 1")
        2, 3 -> println("The number is 2 or 3")
        in 4..6 -> println("The number is between 4 and 6")
        else -> println("The number is not matched")
    }
}

new

Kotlin では Java と違ってコンストラクタの呼び出しに new は不要です。

// Javaの場合
final Foo foo = new Foo();
-------------------------------------------------------------------------
// Kotlinの場合
val foo = Foo()

クラス

クラスとは?

オブジェクトを生成するための設計図やテンプレートとして機能し、その中にはデータ(フィールドや変数)と振る舞い(メソッド)が含まれる概念の一つ。

Kotlin でもクラスの考え方は Java と同じですが、 Kotlin 書くことが少なくすっきりとしています。

// Javaの場合
public class Person {
  private final String firstName;
  private final String lastName;
  private int age;

  public Person(String firstName, String lastName, int age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
  }

  public String getFirstName() {
    return firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public int getAge() {
    return age;
  }

  public void setAge(int age)) {
    this.age = age;
  }

  public String getFullName() {
    return firstName + " " + lastName;
  }
}
// Kotlinの場合
class Person {
  val firstName: String
  val lastName: String
  var age: Int

  constructor(firstName: String, lastName: String, age: Int) {
    this.firstName = firstName
    this.lastName = lastName
    this.age = age
  }

  fun getFullName(): String {
    return firstName + " " + lastName
  }
}

Kotlinでは、デフォルトでpublicが適用されるため、publicキーワードを明示的に書く必要はありません。また、private、protected、internalという他のアクセス修飾子も使用できます。

  • private: クラス内からのみアクセス可能。
  • protected: クラス内とサブクラス内からのみアクセス可能。
  • internal: 同一モジュール内からのみアクセス可能。

Kotlinでは、フィールドを持たず、代わりにプロパティと呼ばれるものを使用します。プロパティは自動的にgetterとsetterを持ちます。そのため、Javaのようにgetterやsetterを明示的に書く必要はありません。

以上の特徴により、Kotlinではコードが簡潔になります。

プロパティ

プロパティ( Property ) はフィールドと getter, setter を合わせたようなもの。

// Javaの場合
final int age = person.getAge();
person.setAge(age + 1);
// Kotlinの場合
val age = person.age
person.age = age + 1

プロパティはフィールドと違い、メソッドのように処理の結果を返すこともできます。
getFullName メソッドを fullName というプロパティに書き変えてみます。

// Javaの場合
public class Person {
  ...

  public String getFullName() {
    return firstName + " " + lastName;
  }
}
// Kotlinの場合
class Person {
  ...

  val fullName: String
    get() {
      return firstName + " " + lastName
    }
}

こうして実装されたプロパティは普通のプロパティと同じように person.fullName で呼び出すことができます。
なお、 val ではなく var とすると、 set を使って setter 相当の実装をすることもできます。

さらに、プロパティの実装が式一つで済む場合は、次のように省略して書けます。

// Kotlin
  val fullName: String
    get() = firstName + " " + lastName

Javaではフィールドをpublicにすると直接アクセスされてしまい、制御やカスタマイズが難しくなりますが、Kotlinではプロパティを使うことで制御やカスタマイズが容易になりますし、インターフェースにプロパティを宣言してオーバーライドすることも可能です。

最後に

サイトを参考にしながら初めてKotlinを触ってみたのですが、ルールが簡単かつJavaと比べ、スッキリとしたコードになり、とても書きやすかったです。

また、過去にJavaで学んだことを復習しながら新しい言語の勉強ができて、一石二鳥になりました。

今回はKotolinの基礎の途中まで学んだことを共有しましたが、今後もKotlinについてなどの学んだことやKotlinでの学んだことを活かしてAndroidアプリの開発などを共有できたら良いなと思います。

参考資料

https://qiita.com/koher/items/bcc58c01c6ff2ece658f

Discussion