17 คะแนน โดย GN⁺ 2025-09-18 | 5 ความคิดเห็น | แชร์ทาง WhatsApp
  • ตอนนี้โปรแกรมแรกของ Java ไม่จำเป็นต้องเริ่มด้วย public static void main(String[] args) อีกต่อไป และสามารถเขียนด้วยไวยากรณ์แบบย่อ void main() ได้
  • ในไวยากรณ์ใหม่นี้ สามารถจัดการอินพุต/เอาต์พุตได้ด้วยการเรียกง่าย ๆ อย่าง IO.readln และ IO.println ทำให้โค้ดตรงไปตรงมาขึ้นมาก
  • ไวยากรณ์ที่ยืดยาวอย่าง new Scanner(System.in), System.out.println จึงไม่จำเป็นอีกต่อไป
  • ความไม่สะดวกที่มีมาตลอด “จบสิ้นลงเสียที” และตอนนี้เมื่อโครงสร้างพื้นฐานของ Java เบาขึ้น กำแพงการเริ่มต้นเรียนรู้ก็จะต่ำลงและเป็นมิตรกับผู้เรียนมากขึ้น

  • ตามธรรมเนียมแล้ว Java ต้องการการประกาศยาว ๆ ว่า public static void main(String[] args) เพื่อเริ่มต้นโปรแกรม
  • แต่ ณ วันที่ 16 กันยายน 2025 การประกาศฟังก์ชัน main ที่ซับซ้อนซึ่งเคยถูกมองว่าเป็นตัวอย่างแรกสุดของ Java ได้ถูกแทนที่ด้วยรูปแบบใหม่ที่เรียบง่ายกว่า
  • วิธีเดิม:
    public class Main {  
        public static void main(String[] args) {  
            Scanner scanner = new Scanner(System.in);  
            System.out.print("What is your name? ");  
            String name = scanner.nextLine();  
            System.out.println("Hello, " + name);  
        }  
    }  
    
  • วิธีใหม่:
    void main() {  
        var name = IO.readln("What is your name? ");  
        IO.println("Hello, " + name);  
    }  
    
  • ที่ผ่านมามันถูกวิจารณ์ว่าเป็นไวยากรณ์ที่ยืดยาวเกินจำเป็นสำหรับผู้เริ่มต้น และต้องท่องจำราวกับเป็น “คาถาวิเศษ”
  • การนำไวยากรณ์แบบกระชับมาใช้ช่วยแก้ทั้ง ความยุ่งยาก และ ความเข้าใจยาก ของการประกาศแบบเดิม ทำให้โค้ดอ่านง่ายขึ้น และลดกำแพงการเริ่มต้นเรียน Java ลงอย่างมาก
    • จะไม่มีการใช้ตัวอย่างพื้นฐานที่ต้องสร้างอ็อบเจ็กต์และเรียกใช้งานที่ซับซ้อนอย่าง Scanner, System.out.println อีกต่อไป

Good Fucking Riddance = “ในที่สุดก็หายไปเสียที โล่งใจจริง ๆ ลาก่อน”

5 ความคิดเห็น

 
kayws426 2025-09-22

ฟังดูเหมือนว่าพอมีวิธีใหม่เพิ่มเข้ามาอีกวิธี ก็เลยบอกว่าวิธีเดิมตายไปแล้ว
จริง ๆ แล้วหมายความว่าไม่สามารถใช้วิธีเดิมได้อีกต่อไป และจำเป็นต้องใช้วิธีใหม่เท่านั้นจริงหรือ?

 
jhk0530 2025-09-19

ว้าว

 
jwh926 2025-09-18

ต้องกลับไปเรียนรู้ Java ใหม่อีกครั้งหรือเปล่า..

 
carnoxen 2025-09-18

เมนตายแล้ว เมนจงเจริญ!

 
GN⁺ 2025-09-18
ความเห็นจาก Hacker News
  • คิดว่าคงจะคิดถึงกระบวนการที่พอโบนัสเวลาแล้วค่อย ๆ เข้าใจโค้ดแปลก ๆ แบบนี้มากขึ้น ตอนที่เรียน Python ก่อนแล้วค่อยย้ายมา Java ตอนแรกไม่รู้เลยว่า type อย่าง void หรือ String[] หมายถึงอะไร เลยรู้สึกว่ามันน่าสนใจ พอได้เรียนเรื่อง type ก็เริ่มเข้าใจ จากนั้นก็ได้เรียนแนวคิดเรื่อง class กับ object แล้วก็เข้าใจว่าทำไม main ถึงต้องอยู่ในรูป static method พอลงลึกไปอีกก็ได้เรียนว่าคลาสนี้ถูกเรียกเมื่อไร ทำให้โค้ดที่ตอนแรกดูเหมือน boilerplate เฉย ๆ เริ่มมีเหตุผลขึ้นมา คิดว่านักพัฒนา Java ที่มีประสบการณ์มากกว่าผมน่าจะอ่านความหมายจากบรรทัดเดียวนี้ได้มากกว่าผมอีกเยอะ แต่ตอนนี้มันหายไปแล้วก็โล่งใจดี

    • โล่งใจจริง ๆ ตลอด 30 ปีที่ผ่านมา การศึกษาด้านซอฟต์แวร์สอนให้นักพัฒนาสร้างความซับซ้อนที่ไม่จำเป็นภายใต้ชื่อของ "วิศวกรรม" ตัวอย่างเช่น นักพัฒนา A สร้างคลาสตามความจำเป็น ไม่ว่าจะเป็น entry point, callback, interface หรืออะไรก็ตาม ผลก็คือเราได้คลาสมา จากนั้นนักพัฒนา B ก็เพิ่ม instance variable เข้าไป ทำให้ทุกอย่างกลายเป็น mutable และเกิด "บ่อโคลนแห่ง implementation" ขึ้นมา ต่อมานักพัฒนาอีกคนเพิ่ม inheritance เพื่อ reuse โค้ด แต่สิ่งนี้ก็สร้างความซับซ้อนเพิ่มและฝันร้ายเรื่อง dynamic dispatch สุดท้ายก็เกิด reference cycle ทำให้ความเชื่อมโยงของ object พันกันยุ่งไปหมด ยิ่งเวลาผ่านไป refactor ก็ยิ่งยากและน่ารำคาญ จนสุดท้ายต้องลบโค้ดทิ้งแล้วเริ่มใหม่

    • ตอนเรียนเขียนโปรแกรมครั้งแรกในมหาวิทยาลัย ผมจำได้ว่าเห็นโค้ดนี้แล้วอาจารย์บอกว่า "ปกติผมจะอธิบายโค้ดทุกส่วนให้ฟัง แต่ส่วนนี้ให้รับไปก่อนก็แล้วกัน" ตอนหลังพอกลับมามองอีกทีแล้วรู้ตัวว่าผมเข้าใจโค้ดนั้นทั้งหมด มันเป็นประสบการณ์ที่เจ๋งทีเดียว ถึงอย่างนั้นตอนนี้ก็ดูเหมือนยุคสมัยกำลังเปลี่ยนไป เลยรู้สึกโล่งมาก

    • จริง ๆ แล้ว static class method ก็แทบจะเป็นการปฏิเสธความจริงที่ว่า entry point เดียวของโปรแกรมไม่จำเป็นต้องผูกกับ class ก็ได้ มีทั้ง C++ และภาษาอย่าง Python, Ruby ที่ยอมรับความจริงแบบ procedural นี้ แต่ Java เหมือนปิดตาผู้ใช้แล้วบังคับเข้าไปอยู่ใน "โลก OOP ที่สมบูรณ์แบบ"

    • ในฐานะคนที่รู้จักแนวทาง class-based แบบเก่าอยู่แล้ว สไตล์ใหม่ ๆ (เช่น unnamed classes ใน Java 21) กลับทำให้เกิดคำถามมากขึ้น สรุปแล้ว Java ที่เคยบอกว่า "ทุกอย่างคือ object" ถูกเปลี่ยนให้เป็นภาษาเชิงกระบวนการจริงหรือเปล่า แล้วถ้าต้องใช้ command-line arguments จะทำอย่างไร ผมแทบจะเลี่ยง Java มาตลอดเลยไม่ค่อยรู้ แต่ถามด้วยความสงสัยจริง ๆ

  • สมัย Java 1.2 เราอ่าน standard input กันแบบนี้ Scanner class นี่สำหรับผมยังใหม่และไม่คุ้น

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String input = in.readLine();
  • ผมก็มีประสบการณ์คล้ายกัน เมื่อก่อนเคยเขียน Java มานานจนคุ้นกับแพตเทิร์น public static void main แต่พอมาเจอวิธีใช้ Scanner กลับรู้สึกแปลก ๆ เลยไม่เคยเข้าใจเหตุผลได้อย่างชัดเจน

  • จากประสบการณ์ของผมที่ทำงานกับโปรเจ็กต์ขนาดใหญ่มาหลายสิบปี วิธีที่เขียน main function แทบไม่มีผลอะไรกับชีวิตประจำวันหรืออาชีพของผมเลย อยากรู้ว่าทุกคนคิดว่าการเปลี่ยนแปลงแบบนี้จะส่งผลจริงมากแค่ไหน

    • ถ้าเป็นนักพัฒนา Android ก็แทบไม่มีแนวคิดเรื่อง main อยู่แล้ว พูดตรง ๆ ผมไม่คิดว่าการที่ Hello World แบบ trivial ดูน่าเกลียด จะเป็นตัวชี้วัดได้ว่าภาษานั้นจัดการเรื่องที่ยากกว่านั้นได้ดีแค่ไหน

    • คนจำนวนมากเริ่มต้นเขียนโปรแกรมด้วย Java และพิมพ์ main ซ้ำเป็นสิบ ๆ ครั้ง โดยไม่รู้เลยว่ามันหมายถึงอะไร

    • สำหรับนักพัฒนาในสายงานจริงอาจไม่ได้มีผลมาก แต่สำหรับมือใหม่มันสำคัญ ผมเคยสอน Java มาก่อน และคาถาวิเศษที่ต้องท่องจำ (boilerplate) ก่อนจะพิมพ์ "Hello, World" ได้ เป็นกำแพงในการเริ่มต้นสำหรับนักเรียนจริง ๆ

    • ถ้าคุณสร้าง command-line interface ก็อาจได้รับผลกระทบบ้าง แต่คนที่ทำ CLI ด้วย Java ก็ไม่ได้มีเยอะนัก

    • ช่วงประมาณ 5 ปีหลังมานี้ ผมไม่เคยเห็น main ใน codebase เลย และแทนที่จะสร้างคลาสใหม่เอง ก็มักจะเป็นการ implement หรือ extend คลาสเฉพาะของ framework มากกว่า

  • JEP 445: Unnamed Classes and Instance Main Methods ถูกปล่อยออกมาใน Java 21
    https://openjdk.org/jeps/445

    • น่าเสียดายที่ฟีเจอร์นี้ถูกทำมาให้ใช้ได้แค่กับโปรแกรมไฟล์เดียว ถ้ายอมให้มี package-level methods หรือวางหลาย class/record ไว้ในไฟล์เดียวกันได้ Java น่าจะดีขึ้นกว่านี้มาก แต่ดูเหมือนเขาไม่ต้องการให้มัน "ส่งผลต่อวิธีเขียน Java code โดยทั่วไป"
  • น่าทึ่งที่หลังจาก 30 ปี ในที่สุด Java ก็วิวัฒนาการมาเป็นภาษาที่ค่อนข้างดีได้จริง ๆ

    • ผมเคยเขียนโค้ดจำนวนมากด้วย Java และ C++ แบบล้วน ๆ ไม่พึ่ง framework ซึ่งตอนนั้น boilerplate น้อยกว่าและง่ายกว่ามาก จุดที่ผมรู้สึกถึงความสะดวกจริง ๆ คือราว 10 ปีก่อนตอนมี lambda เข้ามา หลังจากมี lambda แล้ว ปริมาณโค้ดลดลงและรู้สึกเขียนได้สบายขึ้นมาก Java เคยเป็นภาษาที่ explicit มากเกินไปอยู่นาน และมีการเขียนซ้ำที่ไม่จำเป็นจำนวนมาก เหมือนช่วยได้แค่ตรวจ typo ในเรื่องเล็ก ๆ บรรยากาศแบบนี้อยู่ต่อเนื่องจนก่อน Kotlin จะมา หลังจากนั้นการมี lambda กับ anonymous class ก็ทำให้ประสบการณ์พัฒนาดีขึ้นมาก

    • คำกล่าวที่ว่า Java เป็นภาษาที่แย่มากนั้นเกินจริงไปเยอะ

    • ในทางกลับกัน ผมกลับคิดว่าภาษาอย่าง Python ต่อให้ผ่านไป 30 ปีก็ยังใช้งานไม่สะดวกอยู่ดี

    • เดาว่าคุณอาจไม่เคยเจอภาษาที่แย่จริง ๆ หรือไม่อย่างนั้นเกณฑ์ของคำว่า "ไม่แย่" ก็คงสูงมาก

    • ถึงอย่างนั้น Java ก็ยอดเยี่ยมมากในเรื่อง backward compatibility และระบบจัดการ package

  • นี่คือสิ่งที่ผมเคยพูดไว้ในคอมเมนต์ก่อนหน้านี้ ในฐานะนักพัฒนา Java ผมกลับมองว่า python แปลกกว่า แต่ก็ไม่ได้คิดว่าวิธีปัจจุบันมันแย่ เพียงแต่ถ้ายังไม่เข้าใจพื้นฐานของ abstraction แล้วกระโดดเข้าเขียนโปรแกรมเลย มันอาจไม่ใช่ตัวเลือกที่ดีนักสำหรับ "การเริ่มต้นเขียนโปรแกรม" เมื่อเครื่องมือถูกออกแบบโดยยึดตามเป้าหมายหรือ paradigm ใด paradigm หนึ่ง บางครั้งก็อาจเกิด abstraction แบบสุดโต่งได้ Java ถูกออกแบบโดยเน้น OOP จึงทำให้การคิดเป็นบล็อกอย่าง interface ดูเป็นธรรมชาติ access modifiers ของ method/class ก็แยกชัดเจนตามว่าออกแบบไว้ให้ใครใช้ (public, protected, default, private เป็นต้น) กล่าวคือ การเริ่มต้นกับ Java เริ่มจากการเปิดเผย interface ไปยังผู้ใช้ (programmer) มันอาจดูแปลก แต่ก็อย่างน้อยก็มีความสม่ำเสมอ

    • ไวยากรณ์ที่หนักไม่ได้เกี่ยวข้องกับ OOP โดยตรง ก่อนที่ Java จะเกิดขึ้น ไม่มีนิยาม OOP แบบไหนที่บอกว่า "ฟังก์ชันต้องอยู่นอกคลาสไม่ได้" Sun ปฏิเสธแนวคิดเรื่อง standalone function มานานมาก (static import มาใน Java 5, closure มาใน Java 8, compact source file/instance main เพิ่งมาเอาตอนนี้) ผลก็คือทุกฟังก์ชันยังคงอยู่ภายในคลาสทั้งหมด (เพราะเหตุผลด้านการใช้งานจริงและความเข้ากันได้ ไม่ใช่เหตุผลเชิงปรัชญา) เขาพยายามยืนกรานแนวคิด "ทุกอย่างคือ object" แต่ในทางปฏิบัติก็กลับขัดแย้งด้วยการมี primitive values เข้ามา ไม่มีประโยชน์เชิงปฏิบัติอะไรเลยที่ฟังก์ชันต้องอยู่ในคลาส ตรงกันข้าม ถ้าสามารถนิยาม method ให้กับค่าอย่าง integer ได้ก็น่าจะดีกว่าด้วยซ้ำ อ้างอิงไว้ว่า ภาษา "pure OOP" อย่าง Smalltalk ก็สามารถนิยามฟังก์ชันนอกคลาสได้อย่างอิสระ และยังรันโค้ดได้ตรง ๆ ใน REPL ด้วย
      ลิงก์ที่เกี่ยวข้อง

    • ที่ Hello World สำคัญก็เพราะมันแสดงทั้ง boilerplate ที่ต้องมีเพื่อรันโปรแกรม และโค้ดสำหรับแสดงผลจริงได้พร้อมกัน อีกมุมหนึ่ง ในเรื่องการตั้งค่า build tools บางส่วนก็ไม่ใช่แค่ 'boilerplate' แต่เป็นขั้นตอนสำหรับฝึกใช้เครื่องมือ/ตั้งค่าเครื่องมือด้วย ถ้าอธิบายให้ตรงนั้นตั้งแต่แรกก็ไม่ได้เป็นปัญหาใหญ่อะไร

  • ถ้าแค่ใช้กลเม็ดของ compiler เพื่อสร้างคลาสภายใน ก็เป็นเพียงการเปลี่ยนเพื่อภาพลักษณ์เท่านั้น ถ้ายังไม่ยอมให้มี top-level function อื่น ๆ ได้ สุดท้ายมันก็ยังเป็นแค่กรณีพิเศษที่ดูแปลกอยู่ดี

    • C# รองรับ top level statement ตั้งแต่ 9.0 แต่สุดท้ายภายในก็ถูกแปลงเป็น static method อยู่ดี top level function หลายตัวก็ทำงานคล้ายกัน ตัวอย่างจริง: C# decompiled example
      กลเม็ดแบบนี้เป็นตัวอย่างของการแปลงโดย compiler ที่มีประโยชน์จริง (เช่น closure, async state machine เป็นต้น) การเปลี่ยนครั้งนี้ก็เข้าข่ายเดียวกัน

    • ใน C/C++ ที่มีการใช้ default return 0 เฉพาะใน main() ก็ให้ความรู้สึกแปลกคล้ายกัน

    • ถ้ายอมให้เฉพาะ main เป็น top-level function ได้ แต่ที่เหลือทำไม่ได้ ผมก็ยังมองว่านี่ไม่ใช่การเปลี่ยนแปลงที่ดีนัก

  • ผมไม่เข้าใจว่าทำไมตัวอย่างโค้ด Java ถึงชอบละบรรทัด import กัน ถ้าจะโชว์ความซับซ้อนของ boilerplate ผมว่าต้องใส่ import ให้ครบด้วย

    • ปกติ IDE จะจัดการ import ให้อัตโนมัติอยู่แล้ว เลยไม่ค่อยมีใครใส่ใจ และถ้าเป็นคลาสเกี่ยวกับ IO ในตัวอย่างแบบ compact ก็ไม่ต้องมี import เพิ่ม โค้ดเลยรันได้ตามนั้นจริง

    • Java IDE ส่วนใหญ่จัดการ import ให้อัตโนมัติ

  • ถ้าจะลด boilerplate และทำให้โค้ดกระชับขึ้น โดย abstract entry point public static void main(String[] args) ให้เป็นแนวคิด top-level statement แบบ C# ก็ดูน่าจะดี เลยสงสัยว่าทำไมถึงไม่ทำแบบนั้น

    • แนะนำให้อ่านเอกสาร Paving the on-ramp

    • ถ้า entry point มีอยู่ในฐานะกรณียกเว้นพิเศษ ก็เท่ากับยอมรับข้อจำกัดของ OOP ไปแล้ว อย่างนั้นอาจจะดีกว่าถ้าออกแบบทางเลือกใหม่แบบจริงจังไปเลย

  • ผมคิดว่าการใช้ unnamed class ช่วยให้ทำ global variable ได้ง่ายขึ้น รองรับ hot reload ได้ และไวยากรณ์ก็กระชับขึ้น ตรงนี้ถือว่าดี แต่ในเมื่อ Java file ก็มีข้อจำกัดอยู่แล้วว่าชื่อต้องตรงกับ public class ทำไมไม่ทำให้ส่วน public class X { } เป็น optional แล้วค่อยเขียนเมื่อจำเป็นแทน ผมยังไม่ค่อยเข้าใจว่าทำไมต้องเพิ่ม unnamed class เข้ามา
    compiler ก็ยังแปลงมันเป็นคลาสอย่าง HelloWorld.class อยู่ดี ดังนั้นชื่อนั้นก็เป็นแค่รายละเอียดระดับ implementation และใน source code จริงก็อ้างถึงตรง ๆ ไม่ได้อยู่แล้ว
    https://openjdk.org/jeps/445