👏

Java開発者が勉強したJava vs Kotlin① 基礎文法(変数とNull処理)

2025/03/06に公開

はじめに

ひさしぶりの投稿です!
去年から、JavaとSpringを用いたプロジェクトに参加し、3月末にプロジェクト終わりますが、
Kotlinに興味を覚え始めました。まだ、Javaの中でもマルチスレッド関連の知識は足りてないため、KotlinのCoroutineのような非同期処理までまとめることは難しいですが、自分なりにオンライン講座から勉強した内容をまとめ、シェアしたいと考えました。

変数

var & val

variable.java
int number = 1;
final int number2 = 2;
int onlyDeclare;
variable.kt
var number = 1
val number2 = 2
var onlyDeclare:Int

Javaの場合、データ型の指定が必須だが、
Kotlinの場合、TypeScriptのようにコンパイラから型推論をする。

varは変数、valは定数を表す。
また、初期化をしない場合は型指定をする必要があり、型指定はTypeScriptの似ている。

基本型 & 参照型

wrapper.java
int number = 1;
Integer number2= 1; 
wrapper.kt
var number: Int = 1

Javaの場合、intは基本型、Integerは参照型である。
Integerのようなクラスはラッパークラスで、Javaによりプリミティブ型のデータを包んだり、オブジェクトをまた基本型に変換する。
しかし、Kotlinは基本型と参照型を分けて宣言せず、場合によっては内部で自動的にプリミティブ型として最適化される。

nullable

nullable.java
Integer number= 1;
number = null; 
nullable.kt
var number: Int? = 1
number = null 

Javaの場合、Integerは参照型である。そのためnullを格納することができますが、
Kotlinは基本的には変数にnullを格納することができない。
nullを格納するためには?を付け、nullableとして宣言する必要がある。

instance

instance.java
Human human = new Human("hoge"); 
instance.kt
var human = Human("hoge")

Javaの場合、インスタンスを作成する際にnew演算子を使用する。
Kotlinでは、インスタンスを作成する際にnewを使わない。

kotlinのNull処理

nullチェック1

先ほどのnullableを利用し、nullチェックをしてみる。

nullcheck1.java
  public boolean startsWithR1(String str) {
    if (str == null) {
      throw new IllegalArgumentException("nullが入りました。");
    }
    return str.startsWith("R");
  }
nullcheck1.kt
fun startWithR1(str:String?): Boolean{
   if (str == null) {
      throw IllegalArgumentException("nullが入りました。")
    }
    return str.startsWith("R")
  }

nullチェック2

nullcheck2.java
  public Boolean startsWithR2(String str) {
    if (str == null) {
      return null;
    }
    return str.startsWith("R");
  }
nullcheck2.kt
fun startWithR2(str:String?): Boolean?{
   if (str == null) {
      return null
    }
    return str.startsWith("R")
  }

nullチェック3

nullcheck3.java
  public boolean startsWithR3(String str) {
    if (str == null) {
      return false;
    }
    return str.startsWith("R");
  }
nullcheck3.kt
fun startWithR3(str:String?): Boolean?{
   if (str == null) {
      return false
    }
    return str.startsWith("R")
  }

SafeCall

beforeSafecall.kt
val word : String? = "Ramen"
    println(word.length)

nullable演算子が入ったStringの場合、println(word.length)を出力する場合、
赤い下線が表示され、コンパイルに失敗する。
wordがnullになる可能性があり、NPEが発生する可能性があるからだ。

その場合は?.という演算子を使用する。

Safecall.kt
val word : String? = "Ramen"
println(word?.length) //5

word = null
println(word?.length) //null

wordがnullではない場合、後ろにあるlengthが呼び出され、
nullの場合、そのままnullになるため、NPEを事前に防ぐことがわかる。
まるで、JavascriptのOptional Chainingと似ている。

エルビス演算子

Elvis.kt
val left: String? = null
println(elvis?:right) // right

?:はエルビス演算子という。エルビス演算子の左がnullである場合、Elvis演算子の右の値が格納される。
これから、Safecallとエルビス演算子を利用し、先ほどのNullチェック1,2,3をリファクタリングしてみる。

nullチェック1(Clean)

nullcheck1.kt
fun startWithR1(str:String?): Boolean{
   if (str == null) {
      throw IllegalArgumentException("nullが入りました。");
    }
    return str.startsWith("R")
  }
nullcheck1.kt
fun startWithR1(str :String?): Boolean{
        return str?.startsWith("A") 
            ?: throw IllegalArgumentException("nullが入りました。")
    }

nullチェック2(Clean)

nullcheck2.kt
fun startWithR2(str:String?): Boolean?{
   if (str == null) {
      return null
    }
    return str.startsWith("R")
  }
nullcheck2.kt
fun startWithR2(str:String?): Boolean?{
    return str?.startsWith("R")
  }

nullチェック3(Clean)

nullcheck3.kt
fun startWithR3(str:String?): Boolean?{
   if (str == null) {
      return false
    }
    return str.startsWith("R")
  }
nullcheck3.kt
fun startWithR3(str:String?): Boolean?{
    return str?.startsWith("R"):false
  }

ノットヌルアサーション演算子

例えば、絶対にある値にnullが入らない場合、
エルビス演算子とsafe callで処理を行うことはリソースを無駄にする可能性がある。
その際には!!.演算子を使用する。
!!.はKotlinのコンパイラに左の値はNullではありません。チェックをしないでくださいと意味だ。

nullcheck3.kt
val str = "Ramen"
fun startWithR3(str:String?): Boolean?{
    return str!!.startsWith("R"):false
  }

感想

フロントエンドに興味があるため、JavaScriptとTypeScriptを勉強したことがありますが、
Kotlinって結構TypeScriptと似ていてて、Pythonのように;が要らなくて楽でした。
特にNull-Safetyで、条件分岐を入れずに簡単な演算子でNullチェックを行うことができ、
便利でした。さすが流行ってるには理由がある!

Discussion