Edited at

はじめてのKotlin。Javaと比較してみた

プログラミング言語Kotlinについて少し勉強したので、自分の備忘の為にもJavaとの比較付きでまとめています。

情報は適宜修正・追加する予定です。

*Kotlinのバージョンは1.1、Javaのバージョンは7とします。


変数

Kotlin
Java

var a = 123
int a = 123;

Kotlinは型推論する言語です。明示的に型を付けるときは、

var a: Int = 123

のように変数名の後に:型と書きます。


定数

Kotlin
Java

val NUM_MAX = 123
final int NUM_MAX = 123;

定数も変数と同様に型を省略できます。


Number

Kotlin
Java
bit

Byte
byte
8
123

Short
short
16
123

Int
int
32
123

Long
long
64
123L

Float
float
32
123.4f, 123.4F

Double
double
64
123.4

2進数表記: 0b00001011

16進数表記: 0x0F


Boolean

Kotlin
Java

var b: Boolean = false
boolean b = false;

true
true

false
false

&&
&&

||
||

!
!


String

Kotlin
Java

val str: String = "Hello"
String str = "Hello";


ビット演算子

Kotlin
Java

shl
<<

shr
>>

ushr
>>>

and
&

or
|

xor
^

inv
~


制御構文


if-else

Kotlin

var max: Int

if (a > b)
max = a
else
max = b

Java

int max;

if (a > b)
max = a;
else
max = b;


三項演算子

Kotlin

Kotlinには三項演算子はありません。が、if-elseを使って下記のように書けます。

val a = if (n > 0) x else y

上記は、

val a = if (n > 0) {

x
} else {
y
}

と書くこともできます。これはKotlinのif文は{}ブロックの最後の行の値を返す式として働くためのようです。

Java

int a = n > 0 ? x : y;


when

Kotlin

val x = 2

when (x) {
1 -> println("one")
2 -> println("two")
else -> println("otherwise")
}
// => "two"

val y = 2
when (y) {
1,2 -> println("one or two")
else -> println("otherwise")
}
// => "one or two"

Javaで言うところのswitch文。この他にもKotlin特有の書き方があります

Java

int x = 2;

switch (x) {
case 1:
System.out.println("one");
break;
case 2:
System.out.println("two");
break;
default:
System.out.println("otherwise");
}
// => "two"

int y = 2;
switch (y) {
case 1:
case 2:
System.out.println("one or two");
break;
default:
System.out.println("otherwise");
}
// => "one or two"


for

Kotlin

for (i in 0..5) {

Log.d("TEST", "$i")
}

// => 0
// => 1
// => 2
// => 3
// => 4
// => 5

Java

for (int i = 0; i <= 5; ++i) {

Log.d("TEST", "" + i);
}

// => 0
// => 1
// => 2
// => 3
// => 4
// => 5

Kotlin

デクリメントの場合はdownToというちょっと馴染みのないキーワードを使います。

for (i in 5 downTo 0) {

Log.d("TEST", "$i")
}

// => 5
// => 4
// => 3
// => 2
// => 1
// => 0

Java

for (int i = 5; i >= 0; --i) {

Log.d("TEST", "" + i);
}

// => 5
// => 4
// => 3
// => 2
// => 1
// => 0


関数

Kotlin

fun add(a: Int, b: Int): Int {

return a + b
}

Java

int add(int a, int b) {

return a + b;
}


クラス

Kotlin

class User {

...
}

Java

class User {

...
}


コンストラクタ

Kotlin

class User(name: String) {

private val name = name
}

上記は以下のように書いても同義です。

class User(private val name: String) {

}

Java

class User {

private String name;
public User(String name) {
this.name = name;
}
}

上記の例はメンバ変数に値をセットするだけでしたが、コンストラクタ内で何か処理もしたい時はinitを使います。

Kotlin

class User(private val firstName: String, private val lastName: String) {

private val fullName: String

init {
this.fullName = StringBuilder()
.append(firstName)
.append(" ")
.append(lastName)
.toString()
}
}

この場合は更に以下のように簡潔に書けます。

class User(private val firstName: String, private val lastName: String) {

private val fullName: String = StringBuilder()
.append(firstName)
.append(" ")
.append(lastName)
.toString()
}

Java

class User {

private String firstName;
private String lastName;
private String fullName;

public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.fullName = new StringBuilder()
.append(firstName)
.append(" ")
.append(lastName)
.toString();
}
}


セカンダリコンストラクタ

2つ以上のコンストラクタを持つ場合は下記のように書けます。

Kotlin

class User(private val name: String) {

private var age:Int = 0
constructor(name:String, age:Int) : this(name) {
this.age = age
}
}

Java

class User {

private String name;
private int age;
public User(String name) {
this.name = name;
}
public User(String name, int age) {
this(name);
this.age = age;
}
}


抽象クラス

Kotlin

abstract class AbsPerson {

abstract fun setName(name: String)
}

class Person : AbsPerson() {
override fun setName(name: String) {
...
}
}

Java

abstract class AbsPerson {

abstract public void setName(String name);
}

class Person extends AbsPerson {
public Person() {
super();
}

@Override
public void setName(String name) {
...
}
}


継承

Kotlin

open class A {

open fun v() {}
}

class B() : A() {
override fun v() {}
}

Kotlinではデフォルトでfinalクラス扱いになるようで、継承を可能にするためにはopenキーワードを付ける必要があります。

また、メソッドをオーバーライド可能にするためにもopenキーワードが必要です。

Java

class A {

void v() {}
}

class B extends A {
@Override
void v() {}
}


インタフェース

Kotlin

interface IChangeListener {

fun onChanged(newValue: Int)
}

Java

interface IChangeListener {

void onChanged(int newValue);
}


無名クラス (匿名クラス)

Kotlin

val hoge = Hoge()

hoge.setOnChangeListener(object : IChangeListener {

override fun onChanged(newValue: Int) {
// Something to do
}
})

class Hoge {

private var listener: IChangeListener? = null

fun setOnChangeListener(l: IChangeListener?) {
listener = l
}
}

Java

Hoge hoge = new Hoge();

hoge.setOnChangeListener(new IChangeListener() {

@Override
public void onChanged(int newValue) {
// Something to do
}
});

class Hoge {

private IChangeListener listener = null;

public void setOnChangeListener(IChangeListener l) {
listener = l;
}
}


アクセス修飾子

Kotlin
Java
相違点

public
public
-

protected
protected
Kotlin: 継承していないと同一package内でも参照できない。
Java: 継承していなくても、同一packageなら参照可能。

private
private
Kotlin: インナークラスのprivate変数が参照できない。
java: インナークラスのprivate変数も参照できる。

internal
-
Kotlin: パッケージが違っても同じモジュール内なら参照可能。

アクセス修飾子を省略
アクセス修飾子を省略
Kotlin: publicと同じ。
Java: 同じパッケージ内なら参照可能。

Kotlinにおけるモジュールとは公式サイトから引用すると下記の通りです。


The internal visibility modifier means that the member is visible with the same module. More specifically, a module is a set of Kotlin files compiled together:


  • an IntelliJ IDEA module;

  • a Maven or Gradle project;

  • a set of files compiled with one invocation of the Ant task.



クラスメソッド

Kotlin

Kotlinではstaticメソッドはありません。Companion Objectsという仕組みを使えば実現できますが、公式では下記のようにpackage-level functionで書くことを推奨しています。

package hoge.foo

// package-level function
fun doA() {
...
}

import hoge.foo.doA

class B {
fun doB() {
doA()
}
}

*staticメンバ変数も同様にpackage-levelに書くかCompanion Objectsを使います。

Java

package hoge.foo;

class A {
public static doA() {
...
}
}

import hoge.foo.A;

class B {
public void doB() {
A.doA();
}
}


Companion Objects

Companion Objectsは下記例のようにcompanion object {}でメソッドや変数・定数を囲みます。

Kotlin

class Settings private constructor() {

var useTutorial = false

companion object {

private const val KEY_USE_TUTORIAL = "com.your.domain.USE_TUTORIAL"

private val instance = Settings()

fun getInstance(context: Context): Settings {
val sharedPref = PreferenceManager.getDefaultSharedPreferences(context)
instance.useTutorial = sharedPref.getBoolean(KEY_USE_TUTORIAL, true)
return instance
}
}
}

// 利用例

if (Settings.getInstance(context).useTutorial) {
...
}

Java

final class Settings {

private static final boolean KEY_USE_TUTORIAL = "com.your.domain.USE_TUTORIAL";

private static Settings instance = new Settings();

public boolean useTutorial = false;

private Settings() {
}

public static Settings getInstance(Context context) {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
instance.useTutorial = sharedPref.getBoolean(KEY_USE_TUTORIAL, true);
return instance;
}
}

// 利用例

if (Settings.getInstance(context).useTutorial) {
...
}


列挙型(Enum)

Kotlin

enum class MessageLevel {

DEBUG, INFO, WARNING, ERROR
}

Java

enum MessageLevel {

DEBUG, INFO, WARNING, ERROR
}


Additional

ここからは、アレってKotlinではどうやって書くんだ? というTips的なものを書いていきます。


Class.class

Kotlin

MainActivity::class.java

Java

MainActivity.class


Activity.this

Kotlin

this@MainActivity

Java

MainActivity.this


BufferedReader

BufferedReaderクラスを使ってテキストを読み込む例です。

Kotlinではwhile ((line = reader.readLine()) != null)のような記述ができないため、以下のようにすると良いです。

Kotlin

val reader = BufferedReader(InputStreamReader(inputStream))

val builder = StringBuilder()

try {
reader.readLines().forEach { builder.append(it) }

val str = builder.toString()
}
catch (e: IOException) {

}

Java

BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

StringBuilder builder = new StringBuilder();

try {
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}

String str = builder.toString();
}
catch (IOException e) {

}