ใช้ static ได้ไหม

Static

วันหนึ่งระหว่างทำงานรุ่นน้องที่ทำงานถามว่าผมจะทำ Class แล้วใช้ Method เป็น Static ได้ไหม (static คือ keyword ของ java ที่ทำให้สามารถใช้ method หรือ attribute ได้โดยไม่ต้องสร้าง object) ตอนนั้นในสมองก็ผุดคำนึงตอนเรียนวิชา OOAD (Object-oriented analysis and design) ที่ว่า static is evil ขึ้นมาทันที แต่ตอนนั้นก็ต้องฟังก่อนว่าทำไมต้องใช้ จริงๆถามว่าใช้ได้ไหมคำตอบก็คือว่าได้ จริงๆแล้วจะทำอะไรก็ได้หมดแหละจะ SELECT * FROM TABLE แบบไม่ limit จะตั้งชื่อตัวแปรมั่วๆ หรืออะไรก็ตามแต่ แต่คำถามคือมันสมควรทำไหม ในมุมมองของผมการจะใช้ static ต้องดูงานที่จะใช้กับมันว่าทำไมต้องใช้ อย่างแรกเราต้องทำการแยกระหว่าง Class กับ Object ก่อน

Class Vs Object

ภาพแสดงความแตกต่างระหว่าง Class กับ Object ขอขอบคุณภาพจาก https://www.pinterest.com

ถ้าจะเปรียบเทียบ Class เปรียบเสมือนพิมพ์เขียวหรือกรอบที่บอกว่าสิ่งๆหนึ่งต้องมีค่าอะไรบ้างและสามารถทำอะไรได้บ้างเหมือนกับรูปภาพด้านบน Class Dog เป็นตัวบอกว่าหมาตัวนี้ต้องมีค่า Color, Height, Weight และต้องสามารถ Sit, LayDown ได้เป็นต้น แต่ Class ก็ยังคงเป็น Class เป็นแค่กรอบไม่ได้มีตัวตนจริงๆ การที่จะมี Dog จริงๆปรากฏขึ้นมาเราจะต้องทำการสร้าง Object ขึ้นมาภาษาโปรแกรมคือการ Create instance ขึ้นมา Object ที่ถูกสร้างขึ้นมาจะมีค่าเหมือนกับภาพด้านบนที่เมื่อเรา Create instance ของ Class Dog ออกมาเป็น Rayne (อ่านว่าอะไรไม่รู้) จะเห็นว่า Rayne จะมีค่า Attribute ต่างๆขึ้นมาจริงๆและสามารถเรียกใช้ Method ได้

มีไว้ทำไม Static

คราวนี้คำถามว่าแล้วจะมี Static ไปทำไมล่ะ บางครั้งเรามีบางสิ่งที่ไม่จำเป็นต้องมีตัวตนจริงๆแต่ก็สามารถใช้ได้ยกตัวอย่างง่ายๆของ Java คือ Class Math (ได้ยินชื่อแล้วนึกถึงตอนอ่าน Engineering mathematics 1 เลย) ที่มี method และ attribute ที่เกี่ยวกับการคำนวนไว้อยู่แล้วจะเห็นว่า Math ไม่จำเป็นต้องมีตัวตนจริงๆ (ในความหมายของผมคือ Object ) ก็ได้ (ถ้ามีตัวตนเลขวิ่งเข้ามาผมผมคงกลัวน่าดู)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

// STATIC MAX_LEG

public class Dog {
public static final int MAX_LEG = 4;
....
}

// NORMAL MAX LEG

public class Dog2 {
public int MAX_LEG = 4;
.....
}

/// ANOTHER CLASS USE Dog and Dog2

// STATIC
System.out.println("Dog has max leg : " + Dog.MAX_LEG);

// NORMAL
Dog2 tempDog2 = new Dog2();
System.out.println("Dog has max leg : " + tempDog2.MAX_LEG);

หรือว่าบางที Class อาจจะมีคุณลักษณะบังคับที่ทุก Object ที่ถูกสร้างจาก class นั้นต้องมี และ เราต้องการบอกให้คนที่อ่าน class รู้ว่ามี ตัวอย่างเช่นค่าคงที่บางค่าเช่น เรากำหนดค่า MAX_LEG ของ Dog ให้เท่ากับ 4 เพื่อบอกให้ทั้งจักรวาลรู้ว่า Class Dog อะขามีมากสุดได้ 4 โดยเรียกใช้ผ่าน Class โดยใช้วิธี static แต่วิธีธรรมดาต้องสร้าง Object ขึ้นมาเพื่อถามว่า MAX_LEG มีเท่าไหร่ ลองนึกภาพตลกๆดูเอาละกันว่า อยากจะรู้ว่า Dog มีลักษณะคร่าวๆเป็นยังไงแล้วเราต้องสร้าง Object Dog ขึ้นมา 1 ตัว จากนั้นดูค่าขามากที่สุด พอหมดประโยชน์ก็ทำลาย Dog ทิ้งคงน่าสงสารแย่ (จริงๆคือมันเสียเวลาสร้างและ memory อีกต่างหาก)

ใช้ Static ทุกที่ไปเลย เย้

ตอนผมรู้จัก static ผมก็กะทำอย่างนี้เลยปัญหาคืองานบางงานมันไม่ได้ออกแบบมาให้ใช้ static ลองนึกภาพงานงานนึงนะครับต้องการ print ชื่อคนออกหน้าจอนะครับ ถ้าเขียนแบบ Static จะเป็นแบบนี้

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class People {
public String name;
}

public class PrintPeople {
public static void printPeople(People people) {
System.out.println("People name is : " + people.name);
}
}

// Use it
Perople people = new People();
people.name = "Syntax";

PrintPeople.printPeople(people);

จากภาพจะเห็นว่าแค่จะ Print ถึงกับต้องสร้าง 2 Class มาทำงานแบบนี้ ถามว่าจริงๆผิดไหม ผมว่าไม่ผิดหรอกครับคล้ายๆเราเขียนภาษา C ที่กำหนด struct แล้วเขียน function รับ struct เข้าไปเพื่อ print ออกมา แต่ตอนนี้เราเขียน OOP ที่มันมี method ผูกติดกับ Class แทนที่เราจะมี 2 class เราทำ class เดียวไปเลยสิ

1
2
3
4
5
6
7
8
9
10
11
12
13
14

public class People {
public String name;
public void printPeople() {
System.out.println("People name is : " + name)
}
}

// Use it

Perople people = new People();
people.name = "Syntax";

people.printPeople();

อีกทั้งทุกครั้งที่เราประกาศ static method แล้วเรียกใช้ attribute หรือ method ใน Class ตัวเอง มันจะเป็นการบังคับให้เราต้องให้ attribute หรือ method ที่ถูกเรียกใช้เป็น static ไปด้วย (เหมือนไวรัส) และ ตัว Attribute ที่เป็น public static ที่ไม่ได้ประกาศ final มันก็คือ Global variable ดีๆนี่เอง ใครจะเรียกใช้ ใครจะแก้ก็ได้ตามใจ แก้ตอนไหนก็ไม่รู้ ดังนั้นอันตรายมากที่จะใช้ attribute เป็น public static

สรุป

หลังจากร่ายยาวมานานผมสรุปคร่าวๆได้ประมาณนี้ “เราสามารถใช้ทั้ง static และ ธรรมดาร่วมกันได้แล้วแต่สถาการณ์และความเหมาะสม” และจากนี้จะเป็นวิธีการเลือกใช้ไม่ใช้ static ตอนเขียน code ของตัวผมเองว่าตอนใช้ตอนไหนไม่ใช้

  • static
    1. เราใช้ static กับ Attribute มันเป็นค่าคงหรือค่าที่อยากให้ Class อื่นเห็นและสามารถใช้งานได้ ส่วนใหญ่ผมจะประกาศเป็น public static final type ATTRIBUTE_NAME = X ;
    2. เราใช้ static กับ Method เมื่อมันเป็นการใช้งานระดับ Class ไม่ใช่ระดับ Object ขอให้นึกถึงตอนเรียกใช้ Math หรือ MAX_LEG เป็นต้น
    3. เราใช้ static กับ Method เมื่อเรามองว่าเราสร้าง Class นั้นมาเป็น Util หรือ Function Class ประมาณว่าเป็น Class คอยช่วยทำงานบางอย่างซ้ำๆแบบไม่ต้องมีตัวตน Object ตัวอย่างที่เห็นได้ชัดคือ FileUtils, IOUtils

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

เรื่องของ gitignore

gitignore

ในยุคสมัยใหม่แห่งการเขียน Code แทบทุกคนจะต้องรู้จัก Git ซึ่งเป็นตัว version control ของ Source code ซึ่งทำหน้าที่ดูว่าไฟล์ไหนถูกเปลี่ยน ไฟล์ไหนเพิ่ม ไฟล์ไหนหายไป และทำ version ของ source code เพื่อให้เราสามารถย้อนไปย้อนกลับตัว source code ได้ ซึ่งเป็นที่นิยมมากในปัจจุบัน เพราะใช้งานง่าย ฟรี และมี Community มากมายมหาศาล แล้วตัว gitignore มันคืออะไรล่ะ ตัว gitignore ก็คือไฟล์ที่ชื่อ .gitignore ซึ่งเป็นตัวบอกตัวโปรแกรม git ว่า “เราจะไม่สนใจไฟล์เหล่านี้” ย้ำอีกครั้งว่า “เราจะไม่สนใจไฟล์เหล่านี้” เราจะไม่ track version มัน

พูดมาถึงตรงนี้ก็คงจะมีคำถามว่ามีไปทำไม คำตอบคือ Git นัั้นต้องการเก็บ source code ไม่ได้ต้องการเก็บอย่างอื่น แต่ในโปรเจคที่เรากำลังพัฒนานั้นมันมีหลายอย่างเช่น Lib ไฟล์ที่ compile ไปแล้ว ซึ่งเวลาเราสั่งกับ git ว่ามีไฟล์ไหนเปลี่ยนแปลงหรือยังไม่ได้ tracking เข้า version มันจะแสดงให้เราเห็นด้วย ซึ่งบางทีมันสร้างความรำคาญสำหรับคนที่รู้ว่ามันไม่ใช่ไฟล์ที่ต้องการแต่ดันมาแสดงให้ดู แต่ร้ายกว่าคือคนที่พึ่งหัดเขียนหรือไม่รู้ เขาจะทำการ Add ไฟล์พวกนี้เข้าไปใน git ด้วย ทำให้ตัว repo มันใหญ่ ซึ่งจริงๆ source code อาจจะมีขนาดแค่ 50 KB เท่านั้น ตอนผมเริ่มหัดใช้ git ใหม่ก็เอาไฟล์ lib ขึ้นไปบน git ด้วย เวลา clone ทีนี่รอ 10 กว่านาที

แล้วเราจะต้องมานั่งหาเหรอว่าเราจะไม่เอาไฟล์อะไรบ้าง คำตอบคือต้องครับแต่ไม่มากหรือยากเย็นอะไรขนาดนั้น เพราะมนุษย์โลกจำนวนหนึ่งได้สร้าง Tool ขึ้นมาเพื่อ Gen ไฟล์ gitignore ให้กับเรา ซึ่งสามารถไปใช้งานได้ที่ https://www.gitignore.io/ โดย Tool ตัวนี้จะให้เราใส่ ภาษา หรือ IDE ที่ใช้พัฒนา ตัว Tool จะสร้างไฟล์ .gitnore ออกมาให้ จากนั้นเราก็แค่เอาไปวางที่ directory ที่ source code โปรเจคเราอยู่ เพียงเท่านี้ก็ช่วยเราจัดการกับพวกไฟล์พื้นฐานที่เราจะไม่เอาเข้า git ที่เหลือเราก็ไปเพิ่มเอาเองว่าจะไม่เอาไฟล์ไหนขึ้น git อีก

ตัวอย่างการใช้งาน

กรณีเติมในช่วงว่างเป็น Node

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

# Created by https://www.gitignore.io/api/node

### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env


# End of https://www.gitignore.io/api/node

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

เรื่องของ Exception ตอน 2

Anti pattern Exception

ผมเขียนเกี่ยวกับ Exception ไว้ 3 ตอน คุณสามารถกด Link ด้านล่างเพื่ออ่านที่เกี่ยวกับ Exception ตอนต่างๆได้เลย

ตอนเรียนวิชา Software engineering อาจารย์ประจำวิชาบอกว่า “ถ้าคุณนึกว่าจะเขียน Software ออกมาให้ดียังไงไม่ได้ ให้ลองคิดจากมุมที่ว่า Software ที่ไม่ดีมันมีอะไรบ้าง แล้วคุณจะได้ Software ที่ดีออกมา” พอเริ่มมาทำงานผมจะหาสองสิ่งเสมอตอนเขียน Code คือ หา Best practice กับ Anti pattern แต่ที่ชอบหาคือ Anti pattern เพราะอย่างน้อย Code ที่ออกมาจะไม่แย่

Anti pattern ของ Exception นั้นมีอยู่หลายข้อขนาดว่ามีคนทำ Paper เกี่ยวกับเรื่องนี้เลย

  • Catch Generic

คือการที่เราทำการ Catch Exception ด้วย Exception ที่ใหญ่กว่า Exception ที่ Throw ออกมามากๆ ดังตัวอย่างด้านล่าง

1
2
3
4
5
6
7
File newFile = new File("new_file.txt");
try{
newFile.createNewFile();
} catch(Exception ex) {
logger.error("THIS IS EXCEPTION", ex);
handleFile(ex);
}

จากตัวอย่าง Code จะเห็นว่าการสร้างไฟล์นั้นจะ Throw IOException ออกมาแต่เราไป Catch มันด้วย Exception ซึ่งเป็น Exception บรรพบุรุษ ของ Exception ทั้งหลายดังนั้นมัน Catch หมด ซึ่งการ Catch หมดอย่างนี้มันอันตรายตรงที่แทนที่เราจะจัดการเฉพาะกับ IO Exception กลายเป็นว่าเรา Handle ทุก Exception และเราจะไม่รู้สาเหตุที่แท้จริงของ Exception ว่ามันเกิดอะไรกันแน่ แต่ไม่ใช่ว่ามันจะดักด้วย Exception แบบนี้ไม่ได้นะครับ คือจริงๆเราสามารถดักมันด้วย Exception ใหญ่ได้ในกรณีที่กันตัวโปรแกรมตายจากการไม่ดัก Exception ประมาณว่าดักหมดทุกอย่างที่ต้องดักแล้ว (Check Exception) อย่างอื่นที่เกินคาดหมายก็ดักมันด้วย Catch Exception

1
2
3
4
5
6
7
8
9
10
File newFile = new File("new_file.txt");
try{
logger.error("Problem with create file", ex);
newFile.createNewFile();
} catch(IOException ex) {
handleFile();
} catch(Exception ex) {
logger.error("THIS IS UNCHECK EXCEPTION", ex);
handleError(ex);
}
  • Throws Generic

คือการที่เรา Throw exception ระดับสูงหรือ Exception ที่ไม่ตรงใหญ่ๆออกไป ยกตัวอย่างง่ายๆคือการ Throw Exception ออกไป

1
2
3
4
5
6
7
8
public void controlMachineProcess(URI serverURI) throws Exception {
Machine machine = getMachineFromServer(serverURI);
if (!machine.canProcess) {
throw new Exception("Machine not correct process");
} else {
..........
}
}

ปัญหาของการทำแบบนี้มันจะทำให้เกิดปัญหาของคนที่ต้องการใช้เอาฟังก์ชันนี้ไปใช้จะเกิดคำถามทันทีว่า Exception ที่ว่ามันคืออะไร แล้วจะจัดการยังไง ยิ่งตัว Code นี้อยู่ในระดับ low level แล้วมีคนเรียกใช้มันจากระดับสูงๆ จะมีสักกี่คนไปอ่าน Manual หรือ Source code ว่าตัว Exception ที่โยนออกมาหมายถึงอะไร วิธีแก้ก็ไม่ยากไปหา Exception ที่เหมาะสมกับตัวปัญหานี้

  • Log and Throw

คือการที่เราทำ Catch Exception แล้วทำการ Log จากนั้นทำการ Throw ออกไปอีก

1
2
3
4
5
6
7
8
9
public Customer crateCustomerFromFile(File file) throw IOException {
try {
String data = FileUtils.readFileToString(file, "UTF-8");
return new Customer(data);
} catch (IOException ex) {
logger.error("Problem with input file", ex);
throw ex;
}
}

ปัญหาของการทำอย่างนี้คือเวลาเกิดอย่างนี้เวลาไล่ตามดู Log มันจะเกิดความโคตรงงว่าตกลงมันเริ่ม Error ตรงไหน Stack trace นี่จะมั่วไปหมด ทำให้เราค้นหาต้นเหตุของปัญหายากขึ้นกว่าเดิม ดังนั้นวิธีแก้คือ ถ้าจะ Throw ไม่ต้อง log นะครับ คนข้างนอกเขาจะจัดการเองว่าเขาจะ log หรือจะไม่ log (ถ้าเขาไม่ log ก็ด่าเขาไป)

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

Ref :
https://community.oracle.com/docs/DOC-983543#catchingException
https://arxiv.org/pdf/1704.00778.pdf

เรื่องของ Exception ตอน 1

Exception

ผมเขียนเกี่ยวกับ Exception ไว้ 3 ตอน คุณสามารถกด Link ด้านล่างเพื่ออ่านที่เกี่ยวกับ Exception ตอนต่างๆได้เลย

Exception คืออะไร Exception คือ อาการผิดปกติหรือสถานะที่ไม่ปกติของโปรแกรมที่ไม่ได้อยู่ในการควบคุมของโปรแกรมส่วนนั้น ตัวอย่างง่ายๆคือ เรียกฟังก์ชั่นอ่านไฟล์แต่เกิดปัญหาคือไฟล์ที่จะอ่านไฟล์นั้นไม่มีอยู่จริง ซึ่งฟังก์ชันอ่านไฟล์เขา Design ไว้แค่อ่านไฟล์ไม่ได้ครอบคลุมถึงการดูแลว่าถ้าเกิดไฟล์ไม่มีอยู่จริงจะต้องทำยังไง ดังนั้นคนที่ Design ฟังก์ชั่นอ่านไฟล์เขาจึงใช้ Feature Exception ทำการส่ง Exception ออกไปบอกว่า “ผมเปิดไฟล์นี้ไม่ได้นะไฟล์นี้ไม่มีอยู่จริงอันนี้ผมไม่สามารถตัดสินใจได้ว่าผมจะทำยังไงเมื่อไฟล์ไม่มีอยู่จริง คุณไปตัดสินใจเอาเองก็แล้วกันว่าจะทำไงต่อ”

ผมเชื่อว่าจะต้องคำถามเกิดขึ้นมาในใจ อ้าวทำไมต้องโยน Exception ออกมาทำไมไม่จัดการมันในฟังก์ชันนั้นเลยล่ะ คำตอบก็ง่ายๆครับคือ เขา Design ให้มันไปใช้ได้หลายที่ ประมาณว่าเขียนฟังก์ชันอ่านไฟล์ที่เดียว คุณสามารถเอาไปใช้ได้กับทุกที่ทุกงาน แต่ละงานอาจจะต้องการการจัดการ Exception ต่างกันเช่น โปรแกรมกระโหลกกะลาของผมเวลาเจอ Exception นี้ผมสั่งให้โปรแกรมมแสดงหน้าจอตลกๆว่า “Correct file path ?” แต่บางโปรแกรมเขาอาจจะเป็น GUI แสนสวยพร้อมบอกว่า คุณเลือกไฟล์ที่ไม่มีอยู่จริงนะพร้อมใจดีให้ User กรอก ตำแหน่งไฟล์ใหม่ หากเราไม่ทำเป็น Exception กลางๆก็เท่ากับว่าเวลามีการแก้ไขวิธีการจัดการปัญหาเราต้องไปแก้ฟังก์ชันอ่านไฟล์ด้วย ซึ่งมันไม่ควรเพราะงานสองงานนั้นแยกเป็นคนะลงาน งานอ่านไฟล์ก็อ่านไฟล์ งานจัดการกับความผิดพลาดก็งานจัดการกับงานผิดพลาด

1
2
3
4
5
6
7
8
9
10
11
// EXAMPLE try catch exception
// from file input stream
try {
File file = new File("/root/text.txt");
IOStream input = FileUtils.openInputStream(file, "UTF-8");
/// do someting with input stream
} catch(FileNotFoundException ex) {
System.out.println("Correct file path ?");
} catch (IOException ex) {
System.out.println("Hey my program have a problem with file");
}

เพิ่มเติม FileUtils เป็น Lib ที่ช่วยเกี่ยวกับการจัดการไฟล์ไม่ว่าเปิด ปิด ลบ หรือ อื่นๆ แนะนำให้ใช้จะได้ไม่ต้องมาจัดการเอง

ประเภทของ Exception

ในภาษาแต่ละภาษาที่มี Feature Exception นั้นมีการแบ่งประเภทไว้แตกต่างกันแต่มันก็มีแนวคิดคล้ายคลึงกันโดยผมขอยึดตามตัวของภาษา Java ละกัน java แบ่ง Exception ออกเป็น 2 พวกใหญ่ๆคือ Check exception กับ Uncheck exception

Image of exception from : /www.tutorialspoint.com

Check Exception คือ Exception ที่เราต้องเตรียมจัดการกล่าวคือคนเขียนฟังก์ชันเขามองดูแล้วว่า เฮ้ยมันจะต้องเกิด Exception พวกนี้ขึ้นมาแน่ๆซึ่งเป็นเหตุปกติที่มาจากการใส่ชื่อไฟล์ไม่ถูกต้อง หรือ ต่างๆนาๆ ที่คุณต้องเตรียมจัดการนะตัวอย่างง่ายๆคือ IOException และ FileNotFoundException เป็น Exception ที่คนเขียนฟังก์ชันอ่านไฟล์บอกเราแล้วว่า มันมีแน่ๆเราจึงต้องเตรียมจัดการมันเหมือน Code ข้างบน

Uncheck exception คือ Runtime exception จากภาพเราจะเห็นว่า Runtime exception ก็เป็นหนึ่งใน Exception ตามการ Inheritance แต่ในส่วนของ Rumtime exception เขาได้เพิ่มความสามารถเวลาโดน check ว่าจะต้อง check ไหมให้ไม่ได้ต้อง check โดยใช้คุณสมบัติ Polymorphism (เริ่มนอกเรื่อง) เอาเป็นว่าไอ Uncheck exception มันเป็น Exception แบบไม่ที่ต้องมาบอกว่าต้องจัดการนะโดยส่วนใหญ่มันเกิดจากความผิดพลาดของคนเขียน Code ตัวอย่างง่ายๆคือ NullPointerException พี่ส่ง Null ไปให้คนอื่นใช้ หรือ InexOutOfBoundException พี่อ้างอิงถึง index ที่เกิน Array คือลองคิดดูว่าถ้าเราบอกว่าต้องจัดการ NullPointerException, InexOutOfBoundException เนี่ย Code เรามันจะวุ่นวายขนาดไหนกัน เขาเลยเอามันมาเป็น Uncheck exception ถ้าคุณเขียน Code ดีพอ Save พอเหตุการณ์พวกนี้มันจะไม่เกิดไอพวกนี้คือสิ่งที่คุณ Control ได้มันเป็นสิ่งที่คุณ Control ได้โดยไม่ต้องบอกให้จัดการ

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

Ref :
https://community.oracle.com/docs/DOC-983543
http://www.onjava.com/pub/a/onjava/2003/11/19/exceptions.html
https://www.tutorialspoint.com/java/java_exceptions.htm

รักเธอแล้ว

รักเธอแล้วแสนปวดใจเธอไม่รัก น่าแปลกนักที่ยังรักเธอเสมอ
รักเธอแล้วต้องทุกข์ใจเมื่อพบเจอ ทำได้เพียงแค่มองเธอเดินจากไป
รักเธอแล้วและก็รู้เป็นเพียงฝัน ไม่มีวันจะเป็นจริงขึ้นมาได้
รักเธอแล้วเธอไม่เห็นไม่เป็นไร เพราะหัวใจฉันนั้นได้หลงรักเธอ

Programmerรักเธอแล้ว

รักเธอแล้วแม้จะปวดใจที่เธอไม่รัก ทุกข์ใจที่ทำได้แค่มอง ทั้งที่รู้เป็นเพียงฝัน ทั้งที่รู้ว่าสุดท้ายต่อให้รักเธอมากเพียงใด ความรู้สึกนั้นเธอก็ไม่เห็น แต่จะเป็นไรเล่าเพราะอย่างน้อยเราก็ได้รักเธอแล้ว

ไม่อยาก

ไม่อยากมีเธออยู่ในความทรงจำ

ไม่อยากช้ำที่คิดถึงเพียงแต่เธอ

ไม่อยากเป็นเหมือนคนบ้าคอยพร่ำเพ้อ

ไม่อยากเป็นคนที่เธอไม่สนใจ

Programmerไม่อยาก

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