blog

Kotlin-1の基本を取り戻す

他のいくつかの言語とは異なり、Kotlinの数値は暗黙の拡大変換を持ちません。...

Aug 3, 2020 · 13 min. read
シェア

パッケージの定義とインポート:

  • 定義: パッケージ宣言はソースファイルの一番上にあるべきです。
package com.example.ljy.kotlin001
  • パッケージのインポート
import java.math.BigDecimal
  • 名前が競合する場合は、as キーワードを使用して競合する項目の名前をローカルに変更し、曖昧さを取り除くことができます:
// Message import android.os.Message // NotifiMessage アンドロイド.app.Notification.MessagingStyle.Message” import android.app.Notification.MessagingStyle.Message as NotifiMessage

プログラミングのエントリー・ポイント

fun main() {
 println("Hello world!")
}

アノテーション

 // これは1行のコメントである
 
 /* 
 これは複数行の*abc*/ブロック注釈。
 Javaと異なり、Kotlinのブロック・コメントは入れ子にできる
 */

変数と定数

  1. 宣言: var/val キーワード 変数名: 変数型
    • 型は省略可能で、文末のセミコロンも省略できます。
var aaa: Int=0;
val bbb =1
  1. 変数変数定義: var キーワード
 var x = 5 // 変数は自動的にInt型と推測される
 x += 1 // 変数は変更できる
  1. 不変変数の定義:valキーワード、一度しか代入できない変数
    • Javaのfinal修飾子に似た、一度しか代入できない変数
    • イミュータブルなデータの優先順位
val a: Int = 0
val b = 1 // 変数は自動的にInt型と推測される
val c: Int // 宣言時に初期化されていない場合は、変数の型を指定しなければならない
c = 2

数字:

  • 一般的な型: Byte,Short,Int,Long,Float,Double
  • 一般的な進行
// : 
var num1=123
//16進数: 
var num2=0x2f
// : 
var num3=0b00001011
//8進数はサポートされていない
  • アンダースコアを使うと、数値定数を読みやすくすることができます:
val oneMillion = 1_000_000
  • 他のいくつかの言語とは異なり、Kotlinでは数値の暗黙的な拡張はありません。例えば、Doubleパラメータを持つ関数はDouble値に対してのみ呼び出すことができ、Float、Int、その他の数値に対しては呼び出すことができません。
 fun printDouble(d: Double) {
 println(d)
 }
 val n1 = 1
 val n2 = 1.1
 val n3 = 1.1f
 printDouble(n2)
// printDouble(n1)//ERROR: タイプの不一致
// printDouble(n3)//ERROR: タイプの不一致
  • ナンバークレートは必ずしも均質性を保つものではなく、等価性を保つものです。
val a: Int = 100
val boxedA: Int? = a
val anotherBoxedA: Int? = a
val b: Int = 10000
val boxedB: Int? = b
val anotherBoxedB: Int? = b
//数値のボックス化は必ずしも均質性を保持しない:
//===等号に似ている
println(boxedA === anotherBoxedA) // true
println(boxedB === anotherBoxedB) // false
//等式が保持される:
println(b == b) // true
println(boxedB == anotherBoxedB) // true
  • 明示的な変換
// 実際にはコンパイルされない仮のコード:
val a1: Int? = 1 // ボックス化されたInt (java.lang.Integer)
// val b1: Long? = a1 // 暗黙の変換により、ボックス化されたLongが作成される (java.lang.Long)
// print(b1 == a1) // 驚きだ!これは "false "を出力する。”Longに対するequals()が、もう一方もLongかどうかを検出することを考えると
//数値の幅を広げるために明示的に変換できる
val b1: Long? = a1?.toLong()
println(b1?.equals(a1) ?: (a1 == null))
  • 整数同士の割り算は常に整数を返します。
val x1 = 5 / 2
println("x1 == 2:${x1 == 2}")
//浮動小数点型を返すには、パラメータの1つを明示的に浮動小数点型に変換する
val x2 = 5 / 2.toDouble()
println("x2 == 2.5:${x2 == 2.5}")
val x3 = 5.toDouble() / 2
println("x3 == 2.5:${x3 == 2.5}")
  • ビット演算:ビット演算では、名前付き関数がサフィックスによってのみ呼び出されることを示す特別な文字はありません。
 val x = (1 shl 2) and 0x000FF000
//ビット演算の完全なリスト
//shl(bits) - 符号付き左シフト
//shr(bits) - 符号付き右シフト
//ushr(bits) - 記号の右シフトがない
//and(bits) - ビット単位とヌル単位の比較
//or(bits) - ビットまたは
//xor(bits) - ビット単位で異なるか
//inv() - ビット情報
  • NaN
独自の
println("Float.NaN== Float.NaN:${Float.NaN == Float.NaN}")
println("Float.NaN=== Float.NaN:${Float.NaN === Float.NaN}")
println("Float.NaN.equals( Float.NaN):${Float.NaN.equals(Float.NaN)}")
println("Float.NaN - Float.POSITIVE_INFINITY: ${Float.NaN - Float.POSITIVE_INFINITY}")
//-0.0 0より小さい.0
println("-0.0 0より小さい.0:${-0.0 < 0.0}")
  • 配列
Kotlinでは、配列はArrayクラスを使って表現される。
(演算子のオーバーロード規則に従って、これは [])以下は、TODO()関数、size属性、その他の便利なメンバ関数の使用例である。
//配列はライブラリ関数arrayOfを使用して作成される。
//[1, 2, 3] ライブラリ関数arrayOfNulls()を使用すると、指定したサイズの配列を作成できる。 あるいは、ライブラリ関数 arrayOfNulls() を使って、すべての要素が空の指定サイズの配列を作成することもできる。
//配列のサイズと、与えられたインデックスの各要素の初期値を返す関数の引数を受け取る配列コンストラクタを使うという方法もある:
// 配列を作成する<String> を初期化する ["0", "1", "4", "9", "16"]
val asc = Array(5) { i -> (i * i).toString() }
asc.forEach { println(it) }
//元の型の配列: Kotlin オリジナルの型の配列を表示するための、パッキング・オーバーヘッドのない特別なクラスもある。: ByteArray ShortArray、ShortArray、IntArrayなどである。これらのクラスは
//Array は継承されないが、同じメソッド・プロパティのセットを持つ。また、どちらも対応するメソッドを持っている。
val aar: IntArray = intArrayOf(1, 2, 3)
aar[0] = aar[1] + aar[2]
// の値を最大にする [0, 0, 0, 0, 0] 整数配列の
val arr1 = IntArray(5)
// 例: 配列の値を定数で初期化する
// の値を最大にする [42, 42, 42, 42, 42] 整数配列の
val arr2 = IntArray(5) { 42 }
// 例: ラムダ式を使って配列の値を初期化する。
// の値を最大にする [0, 1, 2, 3, 4] 整数配列の
var arr3 = IntArray(5) { it * 1 }
  • 符号なし整数
//符号なし整数:
//kotlin.UByte : 符号なし 8 0から255までの対照整数
//kotlin.UShort : 符号なし 16 0から65535までの対照整数
//kotlin.UInt : 符号なし32 0から2までの対照的な整数^32 - 1
//kotlin.ULong : 符号なし 64 0から2までの対照的な整数^64 - 1
//kotlin.UByteArray : 符号なしバイトの配列
//kotlin.UShortArray : 符号なし短整数の配列
//kotlin.UIntArray : 符号なし整数の配列
//kotlin.ULongArray : 符号なし整数配列
//符号付き整数配列と同様に、箱詰めのオーバーヘッドなしに配列のようなAPIを提供する。
// :符号なし整数を使いやすくするために、Kotlinはタグ付き整数のフェース値に接尾辞をつけて、指定された符号なし型を示す方法を提供する。
// uとUのサフィックス リテラルの値を符号なしとしてマークする
val b: UByte = 1u // UByte,期待される型が提供されている
val s: UShort = 1u // UShort,期待される型が提供されている
val l: ULong = 1u // ULong,期待される型が提供されている
val a1 = 42u // UInt: 期待される型が提供されていない、定数はUIntに収まる
val a2 = 0xFFFF_FFFF_FFFFu // ULongTODO():期待される型が提供されていない、定数がUIntに適していない
//uLとULという接尾辞は、リテラル値を符号なし整数として明示的にマークする。
val a = 1UL // ULong,期待される型が提供されず、定数がUIntに適していても

文字列テンプレート

  • 文字列スプライシングよりも文字列テンプレートを優先
  • 正規文字列リテラル内にエスケープシーケンスを入れ子にするのではなく、複数の文字列を優先的に使用してください。
  1. テンプレート内のシンプルな名前
var num = 101
val s1 = "num is $num"
println(s1)
  1. テンプレート内の任意の表現
num = 102
val s2 = "${s1.replace("is", "was")},but now is $num"
println(s2)
  1. 複数行の文字列
//文字列のインデントを維持する必要がある場合は、以下のメソッドを使用できる。,
// 作成された文字列が内部インデントを必要としない場合、trimIndentを使用する。,
// 内部インデントでtrimMarginを使用する:
val a1 =
 """
 Foo
 Bar
 """.trimIndent()
println("a1:
$a1")
val a2 = """if(a > 1) {
 | return a
 |}""".trimMargin()
println("a2:
$a2")
  1. 文字列 ˣ の要素には、インデックス演算子を使ってアクセスできます。
for (c in s1) {
 println(c)
}
  1. 文字列リテラル値:
//1. 文字列をエスケープする: エスケープ文字が使える
val s = "Hello, world!
"
//2. 生の文字列: トリプルクォートで囲む
val text = """
 for (c in "foo")
 print(c)
"""

条件式と循環式

  • if
if (num > 0) {
 println(num)
} else {
 println("num < 0")
}
val data = mapOf("name" to "ljy", "email" to null)
// if null   ?:
data["name"] ?: println("name is null")
data["email"] ?: println("email is null")
// if not null   ?.
println("name len = ${data["name"]?.length}")
println("email len = ${data["email"]?.length}")
// if not null and else   ?. :
println(data["name"]?.length ?: "empty")
println(data["email"]?.length ?: "empty")
// ifを式として使う
//Kotlinでは、ifは式である。
//したがって、三項演算子(条件付き ?   : (またはelse)を使う。
fun maxOf(a: Int, b: Int) = if (a > b) a else b
val num = maxOf(a, b)
 //if は、最後の式をブロックの値とするコードのブロックである。
 //ifを文ではなく式として使用する場合、式はelseをサポートする必要がある。
val max1 = if (a > b) {
 print("Choose a")
 a
} else {
 print("Choose b")
 b
}
fun describe(obj: Any) =
 when (obj) {
 1 -> "one"
 "Hello" -> "greeting"
 //同じように扱う必要のあるサポートがたくさんある場合、複数のサポートをまとめてカンマで区切ることができる。
 0, 2 -> "obj == 0 or obj == 2"
 //区間またはセットでない場合
 in 1..10 -> "obj is in the range"
 is Long -> "Long"
 !is String -> "not a string"
 else -> "Unknown"
 }
println("-->${describe(1)}")
println("-->${describe("Hello")}")
println("-->${describe(1L)}")
println("-->${describe(321)}")
println("-->${describe("abc")}")
  • for
val items = listOf("a", "ca", "ac", "bb", "ab", "ba", "c")
//for ループは、イテレータを提供する任意のオブジェクトをトラバースできる 
for (item in items)
 println("for-->$item")
//配列やリストをインデックスでたどりたい場合:
for (index in items.indices)
 println("for-->item at $index is ${items[index]}")
//またはライブラリ関数withIndexを使用する:
for ((index, value) in items.withIndex()) {
 println("the element at $index is $value")
}
//ラベルでbreakやcontinueを制限できる:
loop@ for (i in 1..100) {
 for (j in 1..100) {
 if (i + j == 200) break@loop
 }
}
//ラベルに戻る: Kotlin 関数リテラル、部分関数、オブジェクト式がある。したがって、Kotlinの関数は入れ子にすることができる。 ラベル制限付きreturnにより、外側の関数から戻ることができる。
fun foo() {
 listOf(1, 2, 3, 4, 5).forEach {
 if (it == 3) return // foo()呼び出し元への非ローカルの直接リターン
 print(it)
 }
 println("this point is unreachable")
}
fun foo2() {
 listOf(1, 2, 3, 4, 5).forEach lit@{
 if (it == 3) return@lit // ラムダ式の呼び出し元、つまりforEachループにローカルに返す。
 print(it)
 }
 print(" done with explicit label")
}
//多くの場合、暗黙のラベルを使った方が便利である。 このラベルは、ラムダを受け入れる関数と同じ名前を持つ。
fun foo3() {
 listOf(1, 2, 3, 4, 5).forEach {
 if (it == 3) return@forEach // ラムダ式の呼び出し元、つまりforEachループにローカルに返す。
 print(it)
 }
 print(" done with implicit label")
}
//ラムダ式を無名関数に置き換える方法もある。 無名関数内のreturn文は、無名関数から自分自身を返す。
fun foo4() {
 listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
 if (value == 3) return // 無名関数の呼び出し元、つまりforEachループに部分的に戻る
 print(value)
 })
 print(" done with anonymous function")
}
// 前の3つの例で使われている部分リターンは、通常のループでcontinueを使うのと似ていることに注意してほしい。しかし、breakに直接相当するものはない。
//をシミュレートするには、ネストされたラムダ式のレイヤーをもう1つ追加し、そこから非ローカルに返す:
fun foo5() {
 run loop@{
 listOf(1, 2, 3, 4, 5).forEach {
 if (it == 3) return@loop // runで渡されたラムダ式からの非ローカルリターン
 print(it)
 }
 }
 print(" done with nested loop")
}
//返り値を返す場合、パーサーはラベルを制限した返り値を好む。
//return@a 1
//は「1を返す @a ”,ラベル付き式を返す(@a 1) ”。
  • while
var index = 0
while (index < items.size) {
 println("while-->item at $index is ${items[index]}")
 index++
}
var index2 = 0
do {
 println("while-->item at $index2 is ${items[index2]}")
 index++
} while (index2 < items.size)

間隔の使用

 //- 1. 
num = 100
if (num !in 0..10) {
 println("num 0から10の範囲ではない")
}
//- 2. 
val max = 100
if (num in 1..max + 1) {// :101を含む
 println("num 1~101の範囲")
}
if (num in 1 until max) {//半開き区間:100を含まない
 println("num を1から99の範囲で指定する")
} else {
 println("num 1から99の範囲ではない")
}
//for (i in 0..n - 1) { /* */ } //  
//for (i in 0 until n) { /* */ } //  
//- 3.区間反復
for (it in 1..10) {
 println("x = $it")
}
//- 4.配列を繰り返し処理する
for (y in 1..10 step 2)
 println("y = $y")
for (z in 9 downTo 0 step 3)
 println("z = $z")

その他

  • Null可能な値とNull検出
 fun printNums(vararg numArr: Int, userName: String?) {
 //上記のstr: String?この?はnullでもよいことを意味する
 for (n in numArr) {
 println("numArr-->$n")
 }
 if (userName != null)//null 
 println("userName--->$userName")
 }
 
 printNums(num, userName = null)
  • 型検出と自動型変換の使用
fun getStringLength(obj: Any): Int? {
 if (obj is String) {
 // `obj` 条件分岐内では、自動的に `String`
 return obj.length
 }
 return null
}
val len = getStringLength(s1)
println("$s1<--len-->$len")
  • 型のエイリアシング:
//コードベースで複数回使用される関数型や、型パラメータを持つ型がある場合、コードを未完成としてフォーマットすることはできない。,
// を使用する場合は、型のエイリアスを定義するのが最善である:
typealias MouseClickHandler = (Any, MouseEvent) -> Unit
typealias PersonIndex = Map<String, Person>
  • 遅延属性
//以下と同じ: if(p==null) { p=1+2+3+4+5 }, 最初に使用されたときに読み込まれる
val p: Int by lazy {
 1 + 2 + 3 + 4 + 5
}
println("p --> $p")
  • 拡張関数
 /**
 * 拡張関数を自由に使う
 * 特定のオブジェクトで主に使われる関数がある場合は、そのオブジェクトを受け手とする拡張関数にすることを検討する。
 * APIの汚染を最小限にするために、拡張関数のNULL可能性をできるだけ制限する。
 * 次の例では、Stringクラスに拡張関数addを追加している。
 */
fun String.add(s: String): String {
 return "$this$s"
}
println("abc".add("def"))
  • 単一の例の作成
 /**
 * 単一の例を作成する
 */
object StrConfig {
 //constで変更される定数は、javaで理解される定数である。
 const val name = "Mr.L"
 var s = "str"
}
println(StrConfig.name)
println(StrConfig.s)
  • try/cache
fun test(): Int {
 var result = try {
 12 / 0
 } catch (e: Exception) {
 -1
 }
 return result
}
println("result=${test()}")
  • オブジェクト・インスタンスに対する複数のメソッドの呼び出し
//1.1 クラスを作成する:人物を見る.kt
/**
 * DTOを作成する
 * は Person クラスに以下の機能を提供する。:
 * - すべてのプロパティのゲッター
 * - equals()
 * - ハッシュコード()
 * - toString()
 * - コピー()
 * - すべての属性に対してcomponent1 ......その他
 */
data class Person(val name: String, var email: String)
//1.2 拡張関数を追加する
fun Person.sayHi() {
 println("$name say: Hello World")
}
 //2.クラスオブジェクトを作成する
val person = Person("ljy", "123456@MSN.com")
//3.with複数のメソッドで1つのオブジェクトを呼び出す
with(person)
{
 val s = toString()
 println(s)
 hashCode()
 println(name)
 println(email)
 sayHi()
}
person.email = "aaa"
// person.name="aaa"
  • 汎用情報を必要とする汎用関数に適したフォーム
//1. java
 public final class Gson {
 ......
 public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
 ......
//2. kotlin
inline fun <reified T: Any> Gson.fromJson(json: JsonElement): T
 = this.fromJson(json, T::class.java)
  • ヌル可能なブール値の使用
val bol: Boolean? = null
if (bol == true) {
 println("bol = true")
} else {
 println("`bol` が false または null ")
}
  • TODO():コードを未完成としてマーク
/** Kotlin 注釈フォーマット用の標準ライブラリには、常にNotImplementedErrorを投げるTODO()関数がある。 その戻り値の型はNothingである。,
 * 期待される型に関係なく使えるようにする。 reason引数を受け付けるオーバーロードもある:
 */
fun testTODO(): BigDecimal = TODO("waiting for feedback from accounting")
  • アノテーションのフォーマット
 //注釈は通常、依存する宣言の中で別の行に置かれ、同じインデントを使用する:
@Target(AnnotationTarget.PROPERTY)
annotation class JsonExclude
//パラメータを持たないアノテーションは、同じ行でフォーマットできる:
@JsonExclude @JvmField
var x: String
//パラメータを持たない個々のアノテーションは、対応する宣言と同じ行に置くことができる:
@Test fun foo() { /* */ }
//ファイル注釈: ファイル注釈は、ファイル・コメント、パッケージ・ステートメントの後に来る,
// パッケージを空白で区切る。
///** ライセンス、著作権、その他 */
@file:JvmName("FooBar")
package foo.bar
Read next

Javaフルスタックエンジニア:Javaバックエンドからフルスタック、高度な電子商取引フルスタックシステムビッグクラスへ

コースの最初の週は、完全なコースのシステム計画を発表し、完全なプロジェクトの結果を表示し、プロジェクトの分析、プロジェクトの技術の選択、および小さなプログラムのコンポーネントの開発手法とテクニックを開始します。

Aug 3, 2020 · 2 min read