ข้าม​ไป​ยัง​เนื้อหา

Kotlin ยืม​กล่อง​เครื่อง​มือ​ของ Java มา​ทั้ง​ใบ แล้ว​เปลี่ยน​สาม​อย่าง

คอร์ส​นี้​ไม่​ได้​เริ่ม​ที่​ว่า​ตัวแปร​คือ​อะไร

มัน​เริ่ม​ที่​คำถาม​ที่​มี​ประโยชน์​กว่า — Kotlin ตัดสิน​ใจ​ต่าง​จาก​ภาษา​ที่​คุณ​ใช้​อยู่​ตรง​ไหน และ​มัน​จ่าย​อะไร​ไป​กับ​การ​ตัดสิน​ใจ​นั้น

📦 orderctl — ของ​ชิ้น​เดียวกัน​กับ​อีก​สอง​คอร์ส

คอร์ส​นี้​สร้าง orderctl เครื่อง​มือ​บรรทัด​คำ​สั่ง​ที่​ประมวล​ผล​ออ​เด​อร์​อาหาร ตัว​เดิม​กับ​ที่ คอร์ส Go จาก​ศูนย์ และ คอร์ส Java จาก​ศูนย์ สร้าง​ไว้

การ​เขียน​ของ​ชิ้น​เดียวกัน​สาม​ภาษา ทำให้​คำถาม “ภาษา​ไหน​ดี​กว่า” กลาย​เป็น​คำถาม​ที่​ตอบ​ได้ ด้วย​การ​ชี้​ไป​ที่ code สาม​ชุด​ที่​ทำงาน​เดียวกัน แทนที่​จะ​เถียง​กัน​ด้วย​ความ​รู้สึก

บท​นี้​เป็น​บท​แนวคิด​กับ​การ​ติด​ตั้ง code ที่​รัน​ได้​จริง​มี​แค่ hello world · ของ​จริง​เริ่ม​บท​ที่ 2

ทุก​อย่าง​ที่ Java ทำได้ Kotlin ทำได้ · ที่​ต่าง​คือ​สาม​ข้อ​ที่​ภาษา​บังคับ​ให้​คุณ​เขียน​ไม่​เหมือน​กัน

Go สร้าง​ทุก​อย่าง​ใหม่​หมด ตั้งแต่​ตัว​เก็บ​ขยะ​จนถึง​ตัว​จัด​คิว · Kotlin ไม่​ทำ​แบบ​นั้น มัน​แปล​ลง bytecode ของ JVM แล้ว​เรียก library ของ Java ได้​ทุก​ตัว​โดย​ไม่​ต้อง​ห่อ​อะไร

เรื่องGo เลือกJava เลือกKotlin เลือกบท​ที่​กลับ​มา
ค่าที่​หาย​ไปstruct กับ​ชนิด​พื้น​ฐาน​แตะ​ได้​เสมอnull ได้​ทุก​ที่ ตรวจ​ตอน​รันชนิด​บอก​เอง​ว่า​รับ null ได้​ไหม2
ความ​ผิด​พลาดเป็น​ค่าที่​ฟังก์ชัน​คืน​กลับ​มาexception ที่​บาง​ตัว compiler บังคับ​ให้​จัดการexception ที่ไม่มี​ตัว​ไหนถูก​บังคับ6
การ​เข้า​กับ interfaceดู​จาก​รูป​ร่าง ไม่​ต้อง​ประกาศต้อง​เขียน implements ออก​มาต้อง​เขียน : ออก​มา เหมือน Java5
การ​ใช้​ซ้ำ​โดย​ไม่​สืบทอดฝัง struct แล้ว​ได้ method มา​ฟรีเขียน method ส่ง​ต่อ​เอง​ทุก​ตัวby คำ​เดียว compiler เขียน​ให้5
การ​จัด​รูป​แบบgofmt ที่​ไม่มี​ตัว​เลือกไม่มี​ตัว​ไหน​ใน​กล่องไม่มี​ตัว​ไหน​ใน​กล่อง​เหมือน​กันบท​นี้

อ่าน​ตาราง​นี้​เป็น​สาม​กลุ่ม

  • สาม​แถว​แรก คือ​สาม​อย่าง​ที่ Kotlin เปลี่ยน
  • แถว​ที่​สี่ คือ​ข้อ​ที่ Go มี​ใน​รูป​ของ​ตัว​เอง​อยู่​แล้ว และ Java ไม่มี
  • แถว​สุดท้าย คือ​ข้อ​ที่ Kotlin ไม่​ได้​แก้​อะไร​เลย และ​คอร์ส​นี้​จะ​ไม่​แกล้ง​ทำ​เป็น​ไม่​เห็น

Kotlin มี​ตาราง​อายุ​เหมือน​กัน แต่​มัน​สั้น​กว่า​ที่​คุณ​คาด และ​ครอบ​ของ​แคบ​กว่า​ที่​คุณ​คาด

คอร์ส Java บอก​ว่า​รุ่น​ที่​ได้​รับ​การ​ดูแล​ยาว​เรียก​ว่า LTS และ​ออก​ทุก​สอง​ปี · ฝั่ง Kotlin ไม่มี​คำ​ว่า LTS เลย แต่​มี​ตาราง​อายุ​อยู่​จริง​ใน​หน้า​เอกสาร​รุ่น ใต้​หัวข้อ​ที่​ชื่อ Standard library security support

Kotlin release lineRelease dateEnd of supportLatest bug fix release
2.4June 3, 2026December 3, 20272.4.10

ทั้ง​ตาราง​มี​แถว​เดียว และ​ประโยค​ที่​อยู่​เหนือ​มัน​คือ​ข้อ​ที่​ต้อง​อ่าน​ให้​ครบ​ทุก​คำ

“Starting with Kotlin 2.4.0, the Kotlin standard library for the JVM has an 18–month support window for each release line.”

มัน​ครอบ kotlin-stdlib บน JVM สาม​อย่าง​ที่​มัน​ไม่​ครอบ​คือ

  • ตัว compiler เอง
  • plugin ของ compiler
  • library อื่น​ของ JetBrains

และ​คำ​ที่​หัวข้อ​นั้น​ใช้​คือ security ไม่ใช่ LTS · คอร์ส​นี้​ใช้ Kotlin 2.4.10 ซึ่ง​เป็น​รุ่น​เดียว​กับ​ที่​ระบบ​ตรวจ​ของ​เว็บ​นี้​ตรึง​ไว้ และ​เป็น​แถว​เดียว​ที่​ตาราง​นั้น​มี

เจ็ด​คำ​สั่ง ไม่มี​ตัว​ไหน​จัด​รูป​แบบ​ให้ และ​มี​หนึ่ง​ตัว​ที่​ดึง dependency ได้​จริง

$ kotlinc -version
info: kotlinc-jvm 2.4.10 (JRE …)

ตัวเลข​ใน​วงเล็บ​คือ JDK ที่ compiler กำลัง​รัน​อยู่ ซึ่ง​เปลี่ยน​ตาม​เครื่อง · คอร์ส​นี้​จึง​ผูก​กับ 2.4 เท่านั้น ไม่​ผูก​กับ​ข้อความ​เต็ม

`kotlinc -version` เขียน​ออก stderr และ​ไม่มี​รูป​สอง​ขีด​ให้​ใช้

คอร์ส Java มี​กล่อง​เตือน​เรื่อง java --version กับ java -version ที่​ไป​คนละ​สาย · ฝั่ง Kotlin เรื่อง​เดียวกัน​แรง​กว่า เพราะสอง​คำ​สั่ง​ใน​กล่อง​เดียวกัน​ทำ​คนละ​อย่าง

คำ​สั่งไป​ทาง​ไหน
kotlinc -versionstderr · stdout ว่าง​เปล่า
kotlinc --versionไม่มี​รูป​นี้ · ตอบ error: invalid argument: --version แล้ว​ต่อ​ด้วย info: use -help for more information ทั้ง​คู่​ออก stderr รหัส​ออก 1
kotlin -versionstdout และ​ข้อความ​คนละ​แบบ (Kotlin version 2.4.10-release-377 (JRE …))

สคริปต์​ที่​เขียน V=$(kotlinc -version) จะ​ได้​ค่า​ว่าง แล้ว​เงื่อนไข​ที่​ตาม​มา​ก็​ผ่าน​ไป​เงียบๆ · ถ้า​ต้อง​ดัก​ผล​จริง ให้​เขียน kotlinc -version 2>&1

kotlinc ไม่​ได้​มา​ตัว​เดียว มัน​มา​เป็น​ชุด​เจ็ด​คำ​สั่ง · แต่​เปิด​อ่าน​ข้าง​ใน​แล้ว​มี​ตัว​จริง​ตัว​เดียว

  • kotlinc ตัว​จริง · แปล source เป็น .class หรือ​เป็น jar
  • kotlin ตั้ง KOTLIN_RUNNER=1 แล้ว​เรียก kotlinc · รัน​สิ่ง​ที่​แปล​ไว้​แล้ว และ​เปิด REPL ได้
  • kotlinr ตั้ง​ค่าตัว​เดีย​วกันเป๊ะ แล้ว​เรียก​ตัว​เดียวกัน
  • kotlinc-jvm ไม่​ตั้ง​อะไร​เลย เรียก kotlinc ต่อ​ตรงๆ
  • kotlinc-js กับ kotlinc-wasm เปลี่ยน KOTLIN_COMPILER ไป​เป้า​หมาย​ที่​คอร์ส​นี้​ไม่​แตะ
  • kapt ตั้ง KOTLIN_TOOL เป็น annotation processor รุ่น​เก่า ซึ่ง​คอร์ส​นี้​ไม่​ใช้

หก​ตัว​หลัง​เป็น​สคริปต์​สั้นๆ ที่​ตั้ง environment variable หนึ่ง​ตัว​แล้ว​เรียก kotlinc ต่อ · นี่​คือ​คำ​อธิบาย​ของ​กล่อง​เตือน​ข้าง​บน — kotlinc -version กับ kotlin -version คือ​สคริปต์​เดียวกัน​ที่​เดิน​คนละ​กิ่ง จึง​พิมพ์​คนละ​ที่​และ​คนละ​ข้อความ

ไม่มี​ตัว​ไหน​จัด​รูป​แบบ​ให้ · แต่​เรื่อง dependency ไม่​ได้​ว่าง​เปล่า​อย่าง​ที่​คิด

ถ้า​คุณ​มา​จาก Go คุณ​จะ​มอง​หา gofmt · ไม่มี

ตัว​ที่​คนใช้​กัน​คือ ktlint และ ktfmt ซึ่ง​อยู่​นอก​กล่อง​ทั้ง​คู่ ต้อง​เลือก​เอง ตั้ง​ค่า​เอง · ข้อ​นี้ Kotlin ไม่​ได้​แก้​อะไร​จาก Java เลย มัน​รับ​มรดก​มา​ทั้ง​ดุ้น

ส่วน dependency ต้อง​แยก​สอง​กรณี · สำหรับ​โปร​เจ​กต์ .kt ที่​แปล​จริง ไม่มี​ตัว​ไหน​ดึง​ให้ คุณ​ต่อ -cp เอง จนกว่า​จะ​มี Gradle ใน​บท​ที่ 3

แต่ script .main.kts ดึง​เอง​ได้ และ​ตัว​ที่​ทำงาน​คือ kotlin-main-kts.jar ที่​อยู่​ใน​กล่อง

// ชิ้นส่วน ไม่ใช่โปรแกรมสมบูรณ์
@file:Repository("https://repo1.maven.org/maven2")
@file:DependsOn("org.apache.commons:commons-text:1.12.0")
$ kotlin dep.main.kts
ok Orderctl พร้อม

มัน​ติดต่อ Maven Central จริง​และ​เก็บ​ลง ~/.m2 · แต่​มัน​คือ CLI scripting ตัว​เดิม ที่​ยัง​เป็น Alpha คอร์ส​นี้​จึง​ไม่​สร้าง​อะไร​บน​มัน

สั้น​ที่สุด​ใน​สาม​ภาษา และ​ไม่มี​อะไร​ครอบ​ข้อความ​เลย

สร้าง Hello.kt แล้ว​ใส่​แค่​นี้

fun main() {
println("orderctl พร้อมทำงาน")
}

เทียบ​กับ​สอง​คอร์ส​ก่อน​หน้าที่​พิมพ์​ข้อความ​เดียวกัน

ภาษาสิ่ง​ที่​ต้อง​เขียน​รอบ​ข้อความ
Gopackage main · import "fmt" · func main() · fmt.Println
Java 25void main() · IO.println
Kotlinfun main() · println

println ของ Kotlin อยู่​ใน kotlin.io ซึ่ง​ถูก​นำ​เข้า​ให้​โดย​ปริยาย​ทุก file · ไม่มี​อะไร​ให้​พิมพ์​เพิ่ม

อีก​สอง​ภาษา​มี​ทาง​ลัด​จาก source ถึง​ผลลัพธ์​ใน​คำ​สั่ง​เดียว · Kotlin ไม่มี

ลอง​ท่า​ที่​คุณ​คุ้น​จาก​คอร์ส Java ดู​ก่อน

$ kotlin Hello.kt
error: could not find or load main class Hello.kt

ต้อง​แปล​ก่อน​เสมอ

$ kotlinc Hello.kt -d out
$ kotlin -cp out HelloKt
orderctl พร้อมทำงาน

สังเกต​ว่า​ชื่อ​ที่​พิมพ์​ตอน​รัน​คือ HelloKt ไม่ใช่ Hello และ​ไม่มี​ใคร​เขียน​ชื่อ​นั้น​ไว้​ที่ไหน​เลย

JVM รัน​ได้​แต่ method ที่​อยู่​ใน class · Kotlin มี​ฟังก์ชัน​ลอย​ได้ จึง​ต้อง​มี​ใคร​สัก​คน​สร้าง class ให้

$ ls out
META-INF
HelloKt.class

compiler เอา​ชื่อ file มา​ตัด​นามสกุล​ออก ทำ​อักษร​แรก​เป็น​ตัว​ใหญ่ แล้ว​เติม Kt ต่อ​ท้าย · ทุก​อย่าง​ที่​คุณ​เขียน​ไว้​ระดับ​บน​สุด​ของ file กลาย​เป็น​สมาชิก static ของ class ตัว​นั้น

ส่วน META-INF ข้าง​ใน​มี main.kotlin_module ซึ่ง​เป็น​บันทึก​ที่ Kotlin เขียน​ถึง​ตัว​เอง · ลบ​ทิ้ง​แล้ว​โปรแกรม​ยัง​รัน​ได้​ตาม​ปกติ เพราะ JVM ไม่รู้​จัก​มัน · แต่ kotlinc รอบ​หน้า​อ่าน​มัน เพื่อ​หา​ของ​ระดับ​บน​สุด​ที่ file อื่น​ประกาศ​ไว้ ลบ​แล้ว​การ​แปล file ที่​เรียก​ข้าม​กัน​จะ​ได้ unresolved reference ทั้ง​ที่ .class ยัง​อยู่​ครบ

กฎ​นี้​ไม่​สนใจ​ว่า​คุณ​ตั้ง​ชื่อ file อย่างไร · hello.kt ก็ได้ HelloKt เหมือน​กัน และ my_app.kt ได้ My_appKt โดย​ขีด​ล่าง​ยัง​อยู่​ครบ

นี่​คือ file classfile classclass ที่ compiler ตั้ง​ชื่อ​จาก​ชื่อ file แล้ว​เติม `Kt` ต่อ​ท้าย · `Hello.kt` ได้ `HelloKt` ซึ่ง​เป็น​ชื่อ​ที่​ต้อง​พิมพ์​ตอน​รัน​และ​ที่​โผล่​ใน​ทุก stack trace ทั้ง​ที่​ไม่มี​ใคร​เขียน​มัน​ไว้ · มัน​จะ​โผล่​ใน​ทุก stack trace และ​ใน​ทุก​คำ​สั่ง​ที่​ต้อง​เอ่ย​ชื่อ class ทั้ง​ที่​ไม่มี​บรรทัด​ไหน​ใน source พูด​ถึง​มัน

`.kts` รัน​ตรง​ได้ แต่​คอร์ส​นี้​ไม่​ใช้​มัน

Kotlin มี Kotlin scriptKotlin scriptfile `.kts` ที่ `kotlinc -script` รัน​ได้​ทันที​โดย​ไม่มี build tool · CLI scripting ยัง​เป็น Alpha และ compiler ไม่​พิมพ์​คำ​เตือน​อะไร​เลย​ตอน​รัน คอร์ส​นี้​จึง​ไม่​ใช้​มัน​เป็น​แกน​ของ​บท​ไหน ซึ่ง​เป็น file .kts ที่​รัน​ได้​ด้วย​คำ​สั่ง​เดียว​จริงๆ · hello.kts มี​บรรทัด​เดียว ไม่​ต้อง​มี fun main ครอบ

println("orderctl พร้อมทำงาน (script)")
$ kotlin hello.kts
orderctl พร้อมทำงาน (script)

kotlinc -script hello.kts ก็ได้​ผล​เดียวกัน · สิ่ง​ที่​คำ​สั่ง kotlin รับ​ไม่​ได้​คือ .kt ไม่ใช่ source ทุก​ชนิด

แต่ CLI scripting ยัง​มี​สถานะ Alpha และ compiler ไม่​พิมพ์​คำ​เตือน​อะไร​เลย​ตอน​รัน · คุณ​จึง​ไม่มี​ทาง​รู้​จาก​หน้า​จอ​ว่า​กำลัง​ยืน​อยู่​บน​ของ​ที่​ยัง​ไม่​นิ่ง

คอร์ส​นี้​จึง​ไม่​ใช้ .kts เป็น​แกน​ของ​บท​ไหน · ยกเว้น​ที่​เดียว​คือ build.gradle.kts ใน​บท​ที่ 3 ซึ่ง​เป็น​คนละ​เรื่อง​กัน เพราะ Gradle ประมวล​ผล​มัน​ด้วย​กลไก​ของ​ตัว​เอง

สาม​ภาษา สาม hello world เดียวกัน แล้ว​วัด​ว่า​ปลาย​ทาง​ต้อง​มี​อะไร​บ้าง

flowchart LR
  A["Hello.kt"] -->|"kotlinc Hello.kt -d thin.jar"| D["thin.jar<br/>1,004 ไบต์"]
  A -->|"kotlinc Hello.kt -include-runtime -d hello.jar"| E["hello.jar<br/>5,609,464 ไบต์"]
  D --> C["รันบน JVM เปล่าได้"]
  E --> C
  E -.-> F["kotlin-stdlib<br/>1,841,933 ไบต์"]
  E -.-> G["kotlin-reflect<br/>3,750,100 ไบต์"]
  E -.-> H["annotations<br/>17,536 ไบต์"]

คำ​บรรยาย​ภาพ: hello world ทั้ง​สอง​รูป​รัน​บน JVM เปล่า​ได้​เท่า​กัน · ที่​ต่าง​คือ​รูป​หนัก​มี​ของ​สาม​ใบ​ติด​มา​ด้วย

kotlinc ห่อ​ผล​เป็น jar ได้​เลย และ​มัน​มี​สอง​โหมด​ที่​ให้​ตัวเลข​ห่าง​กัน​มาก

$ kotlinc Hello.kt -d thin.jar
$ kotlinc Hello.kt -include-runtime -d hello.jar
$ ls -l thin.jar hello.jar
สิ่ง​ที่​ได้ไบต์
thin.jar1,004
hello.jar (-include-runtime)5,609,464

-include-runtime ทำให้​ของ​ที่​ส่ง​ต่อ​โต​ขึ้น​ราว​ห้า​พัน​หก​ร้อย​เท่า จาก​หนึ่ง​พัน​ไบต์​เศษ เป็น​ห้า​เมกะไบต์​เศษ

คำ​ตอบ​ที่​คน​ส่วน​ใหญ่​เดา กับ​คำ​ตอบ​ที่​เครื่อง​ให้ ไม่​ตรง​กัน

ลอง​รัน thin.jar บน JVM เปล่า โดย​ไม่มี kotlin-stdlib.jar อยู่​ที่ไหน​เลย

$ java -jar thin.jar
orderctl พร้อมทำงาน

มัน​รัน​ได้ · เหตุผล​อยู่​ใน bytecode

$ javap -c -p out/HelloKt.class
2: getstatic // Field java/lang/System.out:Ljava/io/PrintStream;
6: invokevirtual // Method java/io/PrintStream.println:(Ljava/lang/Object;)V

println ของ Kotlin เป็น inline function · compiler คัด​เนื้อ​ของ​มัน​มา​วาง​ที่​จุด​เรียก แล้ว​สิ่ง​ที่​เหลือ​คือ System.out.println ของ Java ตรงๆ · ชื่อ​เดียว​ที่​ขึ้น​ต้น​ด้วย kotlin/ ใน class file นี้​คือ annotation kotlin/Metadata ซึ่ง JVM ข้าม​ไป​เมื่อ​หาไม่​เจอ

stdlib จำเป็น​เมื่อไร · เปลี่ยน​สอง​บรรทัด​แล้ว​วัด​ใหม่

เปลี่ยน​โปรแกรม​ให้​แตะ​ของ​ที่ inline ไม่​ได้ แค่​นี้​พอ

Needs.kt
fun main() {
val skus = listOf(" tea ", "cake")
println(skus.map { it.trim().uppercase() })
}
$ java -jar needs.jar
Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/collections/CollectionsKt

ใส่ kotlin-stdlib.jar เข้า class path แล้ว​ได้ [TEA, CAKE]

เส้น​แบ่ง​ไม่​ได้​อยู่​ที่​ภาษา มัน​อยู่​ที่​ว่า​คุณ​เรียก​อะไร · hello world ไม่​ต้อง​มี stdlib เพราะ​มัน​ไม่​ได้​เรียก​อะไร​ของ stdlib เลย · แต่​โปรแกรม​จริง​เรียก​ตั้งแต่​บรรทัด​ที่​สอง

ไม่ใช่ stdlib ทั้ง​ก้อน · ตัว​ที่​ใหญ่​ที่สุด​คือ​ตัว​ที่​คุณ​ไม่​ได้​ขอ

นับ​รายการ​ข้าง​ใน hello.jar แยก​ตาม package ระดับ​บน

$ unzip -l hello.jar | awk '{print $4}' | grep '^kotlin/' | cut -d/ -f2 | sort | uniq -c | sort -rn
2432 reflect
157 jvm
153 collections

-include-runtime ไม่​ได้​มัด​แค่ kotlin-stdlib มัน​มัด​สาม​ใบ

ใบไบต์
kotlin-stdlib.jar1,841,933
kotlin-reflect.jar3,750,100
annotations-13.0.jar17,536
รวม5,609,569

รวม​สาม​ใบ​ได้ 5,609,569 ไบต์ ซึ่ง​เทียบ​กับ hello.jar ที่ 5,609,464 แล้ว​ห่าง​กัน​หนึ่ง​ร้อย​ไบต์​เศษ · ส่วน​ต่าง​มา​จาก​การ​บีบ​อัด​และ manifest

kotlin-reflect ใหญ่​เป็น​สอง​เท่า​ของ stdlib และ hello world ไม่​ได้​เรียก​มัน​สัก​บรรทัด · นี่​คือ​ราคา​จริง​ของ​คำ​ว่า “พึ่ง​ตัว​เอง​ได้”

kotlin-stdlibkotlin-stdliblibrary ที่​ต้อง​เดิน​ทาง​ไป​กับ​โปรแกรม​เสมอ เพราะ JVM ไม่มี​ให้ · `-include-runtime` มัด​มัน​เข้า jar จน​โปรแกรม​สาม​บรรทัด​โต​จาก 1,004 เป็น 5,609,464 ไบต์ จึง​เป็น​ของ​ที่​ต้อง​คิดถึง​ตั้งแต่​วัน​แรก แต่​ไม่ใช่​ด้วย​เหตุผล​ที่​คน​มัก​บอก​กัน · Java ได้ IO.println มา​ฟรี​เพราะ java.lang.IO อยู่​ใน JDK · Kotlin ได้ println มา​ฟรี​เหมือน​กัน​เพราะ​มัน inline ทิ้ง · ที่​ไม่​ฟรี​คือ​ทุก​อย่าง​หลัง​จาก​นั้น

ตัวเลข​พวก​นี้​วัด​จาก hello world เท่านั้น อย่า​เอา​ไป​สรุป​เรื่อง​โปร​เจ​กต์​จริง

kotlin-stdlib.jar มี​ขนาด​คงที่ ไม่​ได้​โต​ตาม​โปร​เจ​กต์​ของ​คุณ · โปร​เจ​กต์​ที่​มี code หนึ่ง​หมื่น​บรรทัด​ก็​ยัง​ลาก 1.8 เมกะไบต์​เท่า​เดิม

แปล​ว่า​อัตราส่วน “ห้า​พัน​หก​ร้อย​เท่า” เป็น​เรื่อง​ของ hello world ล้วนๆ · พอ​โปร​เจ​กต์​โต​ขึ้น สัดส่วน​นั้น​หด​ลง​เรื่อยๆ · สิ่ง​ที่​ไม่​หด​คือ​ข้อ​ที่​ว่าคุณ​ต้อง​ส่ง stdlib ไป​ด้วย​เสมอ ซึ่ง​เป็น​ข้อ​ที่ Java ไม่​ต้อง​เจอ

สี่​อย่าง​ที่​ยัง​ไม่มี และ​แต่ละ​อย่าง​มา​ถึง​เมื่อ​มี​เหตุผล​ให้​ต้อง​มี

  • ไม่มี package จึง​ยัง​ไม่มี​โครง​ไดเรกทอรี​ให้​จำ
  • ไม่มี build tool จึง​ยัง​ไม่มี Gradle ให้​อ่าน
  • ไม่มี​เทสต์ ทั้ง​ที่ kotlin-test.jar อยู่​ใน​กล่อง​แล้ว — บท​ที่ 7 จะ​กลับ​มา​ที่​ข้อ​นี้
  • ไม่มี dependency ซึ่ง​จะ​กลาย​เป็น​เรื่อง​น่า​สนใจ​ใน​บท​ที่ 3 · Kotlin ไป​ได้​ถึง​บท​ที่ 2 โดย​ไม่มี build tool เท่ากับ​คอร์ส Java พอดี แต่​จ่าย​ด้วย​การ​แปล​ที่​แยก​เป็น​สอง​คำ​สั่ง

บท​นี้​วาง​กรอบ​และ​ติด​ตั้ง ยัง​ไม่มี feature ของ orderctl เกิด​ขึ้น​จริง

คุณ​รู้​แล้ว​ว่า Kotlin นั่ง​อยู่​บน JVM ตัว​เดิม เปลี่ยน​สาม​อย่าง​ที่​ภาษา​บังคับ แปล​และ​รัน​โปรแกรม​แรก​ได้ และ​รู้​ว่า HelloKt มา​จาก​ไหน

บท​หน้า​เรา​ลง​ของ​จริง — data class และ sealed interface · จุด​ที่​คน​มา​จาก Java ต้อง​ปรับ​ความ​คิดมาก​ที่สุด​คือ init ของ Kotlin ปฏิเสธ​ค่าที่​ผิด​ได้ แต่​ซ่อม​มัน​ไม่​ได้ ต่าง​จาก compact constructor ของ Java ที่​ปฏิเสธ​ก็ได้ ซ่อม​ก็ได้


🔗 อ้างอิง​ต้นทาง​ของ​บท​นี้

บท​นี้​อิง​ต้นทาง​ที่​ลง​วัน​ที่​กำกับ อ่าน​ต่อ​ได้​โดยตรง:

  • Kotlin releases (เข้า​ถึง 2026-08-28) — หัวข้อ Standard library security support · “Starting with Kotlin 2.4.0, the Kotlin standard library for the JVM has an 18–month support window for each release line.”
  • Kotlin component stability (เข้า​ถึง 2026-08-28) — สถานะ​ของ CLI scripting
  • Kotlin command-line compiler (เข้า​ถึง 2026-08-28) — kotlinc -include-runtime และ​การ​รัน​ด้วย kotlin
  • Kotlin/JVM — calling Kotlin from Java (เข้า​ถึง 2026-08-28) — กฎ​การ​ตั้ง​ชื่อ class จาก​ชื่อ file และ @JvmName
  • ตัวเลข​ไบต์​ทั้ง​สาม​ตัว​วัด​เอง​บน kotlinc-jvm 2.4.10 · macOS arm64 เมื่อ 2026-08-28 · รัน​ซ้ำ​ได้​ด้วย​คำ​สั่ง​ที่​ยก​มา​ใน​หัวข้อ​นั้น

เช็กความเข้าใจ — บทที่ 1

ข้อ 1 / 3

ทำไม `kotlin Hello.kt` ถึงตอบ `could not find or load main class`