Basic Java

Page 1

เริ่มตนกับ

Java

ฉบับเริ่มตน (จริง ๆ)

ลั่นฟา ชุมสาย

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


คํานํา หนังสือเลมนี้เขียนขึ้นมาเพื่อเปนแนวทางใหนก ั ศึกษา วิทยาลัยฟารอส ี เทอรน ใชเปนคูมือในการเรียนวิชา หลักการเขียนโปรแกรมคอมพิวเตอร (เบื้องตน) เนื่องจากวาในระยะเวลา สองถึงสามปทผ ี่ า นมา หนังสือที่ ทางภาควิชาคอมพิวเตอรธุรกิจใชเปนหนังสืออางอิงในการเรียนการสอนนัน ้ โดยสวนใหญแลวจะเปน หนังสือที่แตงโดยชาวตางชาติ ทําใหการใชหนังสือเหลานั้นในการประกอบการเรียนของนักศึกษาเปนไป ดวยความลําบาก เพราะตองใชเวลานานในการแปล ถึงแมวาไดรับความชวยเหลือจาก อาจารยหลาย ๆ ทานในภาควิชา ในการชวยชีแ ้ นะ ชวยแปล แตก็เปนไปไดเพียงนอยนิดเทานั้น ผูเขียนไดเล็งเห็นถึง ความสําคัญของการมีหนังสือไวอานเอง ในเวลาที่ไมสามารถเขาหาอาจารยได จึงไดพยายามเขียน หนังสือเลมนี้ขน ึ้ เพื่อใหเปนคูมือที่นักศึกษาสามารถนําไปใชในการคนควาหาความรูในเรือ ่ งของการเขียน โปรแกรมอีกทางหนึ่ง หนังสือเลมนี้ เปนไดเพียงคูมอ ื อางอิงเบื้องตน ในการเขียนโปรแกรมคอมพิวเตอรดวยภาษา Java เทานั้น เนื่องจากวา Java เปนภาษาที่ ถาผูอานตองการทีจ ่ ะรูถ  ึงการใชอยางละเอียด จะตองใชเวลาในการศึกษา คนความากพอสมควร ยังมีหนังสืออีกหลายเลมทีส ่ ามารถนํามาใชเปนแบบอยางในการเขียนโปรแกรมได ผูเขียนหลายทานไดนําเอาบทความ ตํารา และขอชี้แนะในการใชภาษา Java ขึ้นไปเก็บไวใน web site หลายแหงผูอานควรใช web site เหลานี้ชว ยในการศึกษา คนควาเพื่อใหการเขียนโปรแกรมดวยภาษา Java เปนไปไดอยางรวดเร็ว และแมนยํามากยิ่งขึ้น ถอยคําและสํานวนในหนังสือเลมนี้อาจดูแปลก ๆ สําหรับหลาย ๆ ทาน สาเหตุก็เนื่องจากวาผูเขียนใช สํานวนที่ตัวเองถนัด และเปนสํานวนทีผ ่ ูเขียนเองไดสัมผัสมาจากตางประเทศ ซึ่งอาจไมเปนที่ถูกใจของ ผูอานหลาย ๆ ทาน แตผูเขียนขอสัญญาวาจะพยายามทําใหสํานวนเหลานี้เปนสํานวนไทย ๆ ใหไดใน อนาคต อีกสิ่งหนึ่งทีผ ่ ูเขียนไมสามารถหลีกเลี่ยงไดในการเขียนหนังสือเลมนี้ ก็คือ การใชภาษาอังกฤษ ควบคูไปกับภาษาไทยทั้งนี้ก็เพราะวา ศัพททงั้ หลายที่เกี่ยวของกับคอมพิวเตอรนั้น เราไดมาจาก ภาษาอังกฤษ และผูเขียนเองเห็นวาควรทีจ ่ ะใชศัพทเหลานีโ้ ดยตรง โดยไมตองแปล หรือใชศัพทที่ นักภาษาศาสตรชาวไทยไดแปลออกมาใช เพราะจะทําใหเสียเวลาเพราะอยางไรเราก็ทับศัพทเหลานี้อยู แลว ผูเขียนหวังวาหนังสือเลมนี้ จะชวยใหการเรียนเขียนโปรแกรมภาษา Java เปนไปอยางราบรื่นและประสพ ผลสําเร็จสําหรับทุก ๆ ทาน ผูเขียนขอขอบคุณอาจารยในภาควิชาทุกทาน ที่ไดชว ยเปนกําลังใจและชวยชี้แนะในเรื่องของเนื้อหาใน หนังสือเลมนี้ วาควรจะครอบคลุมเรื่องตาง ๆ มากนอยแคไหน ขอบคุณอาจารย ชัยรัตน ขันแกว ทีช ่ วย อานและแกไขคําผิด และขอขอบคุณอาจารยอีกหลาย ๆ ทานที่ไดชวยเหลือและสนับสนุนใหผูเขียน ไดมี โอกาสเขียนหนังสือเลมนี้ ลั่นฟา ชุมสาย เมษายน 2546

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


i

สารบัญ บทที่ 1

บทที่ 2

บทที่ 3

กอนจะถึง Java

1

ทําไมถึงเลือก Java เปนภาษาในการเขียน code เตรียมความพรอม ติดตั้ง JDK การกําหนด path เขียน code แบบ application หรือ applet การสรางโปรแกรม Java ที่เปน application การ execute โปรแกรม HelloWorld การสรางโปรแกรม Java ที่เปน applet การเขียนโปรแกรม Java ดวย EditPlus ที่มาของ Java โดยสังเขป

1 2

ขอมูล ตัวแปร และ การประมวลผล

13

ขอมูล และ ตัวแปร ชนิดของขอมูล Keyword Primitive datatype ตัวอยางการประกาศตัวแปร การกําหนดคาใหกับตัวแปร การกําหนดคาใหกับตัวแปรภายในโปรแกรม การใช final ในการกําหนดคาใหกับตัวแปร อายุ และ ขอบเขตการใชงาน ของตัวแปร การสรางประโยค การประมวลผล การประมวลผลขอมูลที่เปน integer การใช operator ตาง ๆ การประมวลผล short และ byte การเปลี่ยนแปลงขอมูลดวยการ cast การประมวลดวยตัวแปรที่มีจด ุ ทศนิยม การประมวลผลขอมูลตางชนิดกัน การใช Mathematical Functions ตาง ๆ การใชขอมูลที่เปน Character การใชตัวแปรชนิด boolean Logical operator Relational operator การประมวลระดับ bit (shift และ bitwise) การกําหนดคาใหตัวแปรผานสือ ่ นําเขามาตรฐาน

13 14

การประมวลผลแบบวน (Repetition) การตัดสินใจ และ การเปรียบเทียบ ประโยคทีใ่ ช if การใช if ในประโยคที่มีมากกวาหนึ่งประโยค if – else การใช Conditional operator ? : การใช switch การทํางานแบบวน การใช for loop การใช StreamTokenizer การใช while loop การใช do … while

4 5 6 7 8 12

15 16 18 19 23 26 26 29 32 33 35 37 39 43 45 49 51 58 58 60 68 69 72 73 77 80 83

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


ii

บทที่ 4

การใช break และ continue การใช Nested loop การใช labeled continue และ labeled break

86 88 90

การใช Array และ String

96

การใช Array การกําหนดคาเบื้องตนใหกับ Array การอางถึง array ดวยการ clone และการ copy array การใช array แบบยืดหยุน การคนหาขอมูลใน array การคนหาแบบตามลําดับ การคนหาแบบหารสอง การเรียงลําดับขอมูล การสราง array ที่มีขอมูลเปน array การใช array ที่มีขอมูลในแตละแถวไมเทากัน การใช String Array of characters String ใน Java การเปรียบเทียบ String มากกวา นอยกวา การเขาหาตัวอักษรที่อยูใ น String การใช StringBuffer การกําหนดใหขอมูลของ array เปน String บทที่ 5

บทที่ 6

97 101 104 106 106 108 109 111 113 115 116 118 120 121 125 129

Objects และ Classes

133

Class และ การสราง class ตัวแปรที่เปนสมาชิกของ class Method การเขาหาตัวแปร และ method ของ class การสราง method กระบวนการที่เกิดขึ้นเมื่อมีการใช parameter list การสงคาแบบ pass by value การสงคาแบบอางอิง การกําหนดนโยบายการเขาหาสมาชิกของ class Constructor อีกครั้ง การเรียก constructor จาก constructor การ overload method การสราง class ภายใน class Package การสราง package

134 136 136 138 140 141 143 149 150 153 155 156 162

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ การใช this และ super() การใช protected การ override method Polymorphism การสง และ รับ object การสราง interface

168 168 171 175 179 181

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


iii บทที่ 7

บทที่ 8

การตรวจสอบและดักจับ Error (Exceptions)

188

การ throw exception การใช try และ catch การใช try และ catch ใน loop การใช printStacktrace() การใช throw กับ try การสราง exception ใชเอง

188 190 192 192 195 198

Streams I/O

204

การใช File การใช FileNameFilter Input และ Output streams การใช FileReader การใช FileInputStream และ read() การใช StreamTokenizer กับ FileReader ขอดีของการใช BufferedReader การใช delimiter กับ text file การใช FileWriter และ PrintWriter Binary file การใช DataInputStream และ FileInputStream การใช DataOutputStream และ FileOutputStream การใช writeUTF() และ readUTF() การใช PrintWriter เพื่อผลลัพธที่สวยงาม การใช writeChars() การสรางและใช Random-access file การใช seek() การ update record

205 208 210

ตารางตาง ๆ ตาราง ตาราง ตาราง ตาราง ตาราง

211 213 217 218 218 221

224 228 229 233 234 240

ASCII และ UNICODE (บางสวน) Constant ที่ใชบอย ๆ ในโปรแกรม ชนิดของขอมูล Escape sequences Format ตาง ๆ สําหรับขอมูลที่เปนตัวเลข

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


ในบทที่หนึ่งนี้เราจะมาดูการติดตั้งเครื่องมือทีใ่ ช ในการพัฒนาโปรแกรมดวยภาษา Java ตัวอยางการ เขียนโปรแกรมในรูปแบบของ application และ การเขียนโปรแกรมในรูปแบบของ applet หลังจากจบบทนี้แลว ผูอานจะไดทราบถึง o o o o o o

การติดตั้งเครื่องมือที่ใชในการพัฒนาโปรแกรมในภาษา Java การเขียนโปรแกรมในรูปแบบของ application การเขียนโปรแกรมในรูปแบบของ applet การเขียน HTML ไฟลทใี่ ชในการ execute applet การเขียนโปรแกรม Java ดวย EditPlus ประวัตค ิ ราว ๆ ของภาษา Java

ทําไมถึงเลือก Java เปนภาษาในการเขียน code Java เปนภาษาที่นักพัฒนาโปรแกรมสามารถทีจ ่ ะเขียน code เพียงครั้งเดียว แลวนําไปใชไดกับเครื่อง computer ชนิด (platform) ตาง ๆ ได โดยไมตอง compile ใหม เชน ถาเราเขียนโปรแกรมบนเครื่อง pc เราสามารถทีจ ่ ะนําเอา code ที่ได compile เรียบรอยแลวไป execute ในเครื่องอื่น ๆ ที่ไมใช pc ได เชน apple, linux, unix, หรือ อื่น ๆ ที่มี JVM หรือ Java Virtual Machine อยู Java เปนภาษาที่ไดถูกพัฒนาขึ้นเพื่อสนองตอการพัฒนาโปรแกรมในรูปแบบของการเขียนโปรแกรมที่ เรียกวา OOP หรือ Object-Oriented Programming ซึ่งเปนภาษาที่ชวยใหการพัฒนาโปรแกรมมีความ ยืดหยุนสูง ผูเขียน หรือ ผูพัฒนาสามารถที่จะสนองตอบความตองการของผูใช (user) ไดมากกวาการ พัฒนาในลักษณะของการเขียนโปรแกรมแบบเดิม (procedural language programming) และที่สาํ คัญ อีกอยางหนึ่งก็คือ Java เปนภาษาที่ไมตองเสียคาใชจายใด ๆ เลย เราสามารถที่จะ download โปรแกรม สําหรับการพัฒนาไดจากบริษท ั Sun Micro System หรือทีอ ่ ื่น ๆ ที่ทาง Sun ไดอนุญาตใหมีการ download ได กอนที่เราจะเขียนโปรแกรมดวย Java เราตองมีอะไรบาง 1. เชนเดียวกันกับการเขียนโปรแกรมในภาษาอื่น ๆ เราตองมี Text Editor ที่ใชสรางและเก็บ source code 2. JDK (Java Development Kit) ซึ่งมีหลาย version ลาสุดในขณะที่เขียนตําราเลมนี้ คือ J2SE 1.4 ซึ่ง download ไดที่ http://sun.java.com เราตองใช JDK ในการ compile โปรแกรมที่เราไดเขียน ขึ้น 3. Java VM หรือที่เรียกวา Java Virtual Machine ซึ่งเปนตัวกลางที่เปลีย ่ น code ที่ไดจากการ compile เปน code ที่สามารถ execute บนเครื่องตาง ๆ (code ที่เครื่องนัน ้ ๆ รูจัก – machine code) โดยปกติ VM จะถูกติดตั้งพรอมกับ JDK ถาเรามีอุปกรณทั้งหมดที่ไดกลาวมาแลว ขั้นตอนตอไปที่เราตองทําเพื่อใหการพัฒนาโปรแกรมของเรา เปนไปไดดวยความเรียบรอย (ไมมีอุปสรรคทีค ่ าดไมถึง) เราตองเตรียมความพรอมของเครือ ่ งกอน


บทที่ 1 เริ่มตนกับ Java

กอนจะถึง Java

2

เตรียมความพรอม (สําหรับ pc) 1. ติดตั้ง JDK 2. กําหนด path ภายในเครื่องเพื่อใหการ compile และ execute (run) โปรแกรมเปนไปได – ถาเราไม กําหนด path เครื่องของเราจะไมรูจักคําสั่งตาง ๆ ที่ Java ใช ติดตัง ้ JDK เมื่อ download JDK มาแลวการติดตั้งก็ทําไดงาย เนื่องจาก JDK เปนไฟลที่เราเรียกวา self-extracting file คือ ไฟลทจ ี่ ะติดตั้งโดยอัตโนมัติเมื่อเรา execute (doubling click หรือ ดวยวิธีการอื่น ๆ เชน click บน icon ของ file แลวกด enter) สําหรับไฟล j2se1.4.1 นั้นมีขนาดประมาณ 35.9 MB ซึ่งเปนไฟลที่ ใหญพอสมควร และใชเวลานานในการ download (ถา speed ในการ download ไมดีพอ) ซึ่งเมื่อขยาย ออกจะมีขนาดประมาณ 64.6 MB เพราะฉะนัน ้ เราตองเตรียมเนื้อที่ไวใหเหมาะสมในการ install JDK ถา หากวาเนื้อที่ในการจัดเก็บมีนอย เราก็ควรใช JDK version อื่น ๆ ที่มีขนาดเล็กกวา การกําหนด path ถาการพัฒนาโปรแกรมเปนการพัฒนาบนเครือ ่ ง Windows 9x การกําหนด path ก็สามารถทีจ ่ ะทําไดดว ย วิธีการตาง ๆ ดังนี้ 1. เปดไฟล autoexec.bat แลวเพิ่ม path ที่ไดติดตั้ง JDK ไว ซึ่งถาเราติดตั้ง J2SDK 1.4.1 ไวใน drive c การกําหนด path ในไฟล autoexec.bat ก็ทําไดดังนี้ ใสคําสั่ง set path=c:\j2sdk1.4.1\bin ในบรรทัดใหมถา ยังไมมีมีคําสั่ง set path อยูเลย แตถา มีการ ใช คําสั่ง set path อยูแลวก็ใหใส ; (semicolon) หลังตัวสุดทายของ path แลวจึงใส c:\j2sdk1.4.1\bin 2. หรือเราอาจกําหนด path ทุกครั้งกอนการเขียนโปรแกรม (ถาเราไมไดกําหนดในไฟล autoexec.bat) โดยไปที่ Command Prompt (หรือทีร่ ูจักกันในคนรุนเกาวา dos window) แลวก็ set path บน (dos) Command Prompt

3. ทําการพัฒนาโปรแกรมใน directory ที่มี JDK อยู เชนเปลี่ยน drive ไปที่ c:\j2sdk1.4.1\bin แลว เริ่มทํางานใน directory นี้ ไฟลทุกตัวที่เกี่ยวของกับการเขียนโปรแกรมจะตองเก็บไวที่นี่ – วิธีนี้ ไม แนะนํา เพราะจะทําให directory ของ java เปรอะไปดวยไฟลที่เราเขียนขึ้นเอง ถาเราใช Windows XP หรือ Windows 2000 การกําหนด path ทําไดดวยขั้นตอนตอไปนี้ (Windows XP และ Windows 2000 ใชคําสั่งที่แตกตางกันนิดหนอย ตัวอยางทีท ่ ําใหดูนี้ เปนการกําหนด path บนเครื่อง ที่ใช Windows XP) 1. กดปุมขวาของ mouse บน icon My Computer (หรือ ไปที่ปม ุ start ที่มุมลางซายของจอแลวเลือก My Computer) แลวเลือก Properties

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัย ฟารอีสเทอรน


บทที่ 1 เริ่มตนกับ Java

กอนจะถึง Java

3

2. กดปุม advanced บน System Properties

3. กดปุม Environment Variables

4. ใน System Variables เลือกขอความที่ขึ้นตนดวยคําวา Path

5. เมื่อกดปุม Edit ก็จะไดหนาจอดังที่เห็น

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัย ฟารอีสเทอรน


บทที่ 1 เริ่มตนกับ Java

กอนจะถึง Java

4

6. เติม ; (semicolon) ถายังไมมี แลวจึงใส path ที่ได install JDK ไว เสร็จแลวกดปุม OK เพื่อใหระบบ บันทึกการเปลีย ่ นแปลงที่ไดทาํ ขึ้น หลังจากที่ไดกาํ หนด path ใหกับเครื่องที่เราจะใชในการเขียนโปรแกรมแลว ขั้นตอนตอไปก็ขึ้นอยูกับ ผูเขียน การพัฒนาโปรแกรมก็ทําไดโดยไมตองวุนวายกับการกําหนด path ตาง ๆ อีก (ยกเวนเสียแตวา path ที่ไดกําหนดขึ้นไมมีอยูจริง – เราก็ตองกลับไปเริ่มตนใหม พรอมกับ path ที่มีอยูจริง) ทั้งนี้ทั้งนั้น ผูพฒ ั นาโปรแกรมตองเลือกเองวา วิธีไหนเหมาะสมทีส ่ ุด ถาตองใช Java อยูบอย ๆ และ สม่ําเสมอก็ควรที่จะเลือกกําหนด path แบบถาวร เพื่อจะไดไมตองเสียเวลากับการกําหนด path สิ่งทีส ่ ําคัญอีกสิ่งหนึ่งที่ขาดไมไดในการทดสอบและ execute code ที่เขียนขึ้นดวย Java ก็คือ JRE หรือ ที่เรียกวา Java Run-time Environment ถาเรานําเอา code ที่ไดผานการ compile จาก JDK แลวไป execute บนเครื่องที่ยังไมไดติดตั้ง JRE ผลลัพธก็คือ execute ไมได แตถา เครื่องนั้นไดรบ ั การติดตั้ง JDK ก็จะไดรับการติดตั้ง JRE พรอมกันไปดวย ดังที่ไดกลาวไวกอ  นหนานี้ สาเหตุที่ Sun ทําแบบนี้ก็เพราะวา หลาย ๆ คนอาจไมใชผูพัฒนา Java โปรแกรมแตเปนผูใ ชโปรแกรมที่เขียนขึ้นดวย Java ก็ได ดังนั้นหาก เครื่องใด ๆ ตองใชโปรแกรมทีเ่ ขียนขึ้นดวย Java บอย ๆ ก็ตอง download JRE มาไวที่เครือ ่ งดวย เขียน code ทีเ่ ปน application หรือเขียน code ที่เปน applet Applet เปน code ที่เขียนขึ้นมาเพื่อใหสามารถทีจ ่ ะ execute ใน web browser ผานทาง HTML ไฟล ซึ่ง โดยทั่วไปมักจะมีขนาดเล็ก เพื่อใหการ download applet ทําไดรวดเร็วยิง่ ขึ้น สวน application เปนการ execute ไฟลผานทาง command line ดังนั้นขนาดจึงไมเปนอุปสรรค (เพราะไมตองมีการ download) หนังสือเลมนี้จะแสดงโปรแกรมตัวอยางดวยการเขียน code ในรูปแบบของ application เครื่องมือ หรือ คําสั่ง (SDK tools) ที่ตอ  งใชในการพัฒนาโปรแกรม Java Development Kit ไดถูกเปลี่ยนใหมช ี อ ื่ เปน J2SDK – Java 2 Software Development Kit ดังนั้น เราจะใชชื่อเครือ ่ งมือในการพัฒนาโปรแกรมนี้สลับกันไปมา แตใหตั้งสมมติฐานวาทั้งสอง ตางก็เปน เครื่องมือที่ใชในการพัฒนา Java โปรแกรมเชนเดียวกัน javac

เปนเครื่องมือทีใ่ ชในการ compile (compiler) ทีท ่ ําการเปลีย ่ น source code ที่เรา เขียนขึ้นใหเปน byte code

java

เปนเครื่องมือทีใ่ ชในการ execute byte code สําหรับโปรแกรมที่เขียนขึ้นในแบบของ application

appletviewer เปนเครื่องมือทีใ่ ชในการ execute โปรแกรมที่เขียนขึ้นในแบบของ applet ยังมีเครื่องมืออีกหลายตัวที่ java มีให แตตอนนี้เราจะใชเฉพาะเครื่องมือทีไ ่ ดกลาวไวแคสามตัวนี้ เทานั้น การพัฒนาโปรแกรมทั้งที่เปน application และ applet นั้นจะมีขั้นตอนที่แตกตางกันพอสมควร ดังแสดง ใหเห็นในภาพที่ 1-1 และในภาพที่ 1-2 ในการเขียน code นั้นเราจะตองมี editor ที่เปน text editor กลาวคือเปน editor ที่ไมมีการเก็บ format ตาง ๆ ของตัวอักษรดังเชนที่ Microsoft Word เก็บ แตจะเก็บ เปนรหัส ASCII ที่ SDK สามารถอานและ execute ได สมมติวาเรามี text editor และ SDK แลวการ พัฒนาก็เปนไปตามขั้นตอนที่แสดงในภาพทั้งสอง

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัย ฟารอีสเทอรน


บทที่ 1 เริ่มตนกับ Java

กอนจะถึง Java

Text Editor

5

Java Class File First.class

Javac

Java Source File First.java Java

Java Program Output

ภาพที่ 1-1 ขั้นตอนการพัฒนาโปรแกรมที่เปน application

Text Editor

Java Class File First.class

Javac

Java Source File First.java

appletviewer

HTML file First.html

Java Program Output

ภาพที่ 1-2 ขั้นตอนการพัฒนาโปรแกรมที่เปน applet

การสรางโปรแกรม Java ทีเ่ ปน application สมมติวาเราเลือกใช text editor ตัวใดตัวหนึง่ ที่มีอยูมากมาย ทั้งที่ free และทั้งที่ตองจายเงินซื้อมา เราก็ มาลองเริ่มเขียนโปรแกรมตัวแรก กันเลยดีกวา เพื่อใหเขาใจไดงายถึงขั้นตอนและที่มาที่ไปในการเขียนโปรแกรมดวยภาษา Java เราจะเขียนโปรแกรมที่ ไมทําอะไรมากมายนัก เพียงแตสงขอมูลไปยังหนาจอเมื่อ user เรียกใช (execute) โปรแกรมนี้ เราจะตั้ง ชื่อโปรแกรมนี้วา HelloWorld.java และมีขอมูลดังนี้ class HelloWorld { public static void main(String[] args) { System.out.println("Hello World"); } } ผูอานยังไมตองกังวลกับความหมายของ keyword ตาง ๆ ทีเ่ ห็นในตอนนี้ หลังจากที่เขียนโปรแกรมไดสัก พักหนึ่ง ผูอานก็จะเขาใจถึงความหมายเหลานี้ดีขึ้น แตตอนนี้ตองเขาใจวาไฟลที่เราเขียนขึ้น มีนิยามของ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัย ฟารอีสเทอรน


บทที่ 1 เริ่มตนกับ Java

กอนจะถึง Java

6

class ที่เราเขียนขึ้นชื่อ HelloWorld ซึ่ง Java กําหนดไววา ชื่อของ class และชื่อของไฟลที่เก็บ code ของ class นี้จะตองเปนชื่อเดียวกัน class นี้มี method อยูหนึ่งตัวชื่อ main() เมื่อเรา execute โปรแกรมนี้ JRE จะคนหา method ที่ชื่อ main() เพื่อทําการ execute ทั้งนี้ method main() จะตองมี keyword ทีช ่ ื่อ public, static, และ void อยู รวมไปถึง parameter ที่เปน array ที่เก็บ String ดวย ถาผูอานเคยเขียนโปรแกรมดวย ภาษา C หรือ ภาษา C++ มากอนก็จะเห็นถึงความคลายคลึงกันของ method main() นี้ Parameter ของ method main() ที่เปน String[] args หมายถึง command-line argument ตาง ๆ ที่ ผูใชโปรแกรมสงผานไปยังตัวโปรแกรมเพื่อเอาไวใชในการทํางานตาง ๆ ซึ่งเราจะยังไมกลาวถึงในเวลานี้ ในตัว method main() เองมีประโยคที่ขึ้นตนดวย System.out.println("…") ซึ่งเปนคําสั่งที่ใชสง ขอความไปยัง System.out ที่โดยทั่ว ๆ ไปก็คือ console window หรือที่เรียกกันติดปากวา dos window หรือ dos prompt ดังตัวอยางที่แสดงใหเห็นในภาพที่ 1-3

ภาพที่ 1.3 การ compile และ run โปรแกรม

การ compile โปรแกรม HelloWorld ดังเชนทีแ ่ สดงใหเห็นในภาพที่ 1-3 การ compile ไฟลที่เขียนขึ้นตองใชคําสั่ง javac ตามดวยชื่อไฟล พรอมกับนามสกุล ดังนี้ javac HelloWorld.java ในการ compile ทุกครั้งเราจะตองไมลืมใสนามสกุลใหกับไฟลที่เราไดเขียนขึ้น ไมเชนนั้นแลว compiler จะฟอง โดยการสง error message ใหเราเชน ถาเรา compile ไฟล HelloWorld โดยไมใส .java เราก็ จะได error ดังนี้ E:\bc221Book\source>javac HelloWorld javac: invalid flag: HelloWorld Usage: javac <options> <source files> where possible options include: -g Generate all debugging info -g:none Generate no debugging info -g:{lines,vars,source} Generate only some debugging info … … … (ผูเขียนไดตัดขอความบางสวนที่ java ฟองออก - ใช … แทน) การ execute โปรแกรม HelloWorld สมมติวาเรา compile โปรแกรม HelloWorld โดยไมมี error ใด ๆ เกิดขึ้นการ execute โปรแกรมก็ทําได ดวยคําสั่ง java ตามดวยชื่อไฟล ดังนี้ java HelloWorld และก็จะได output ดังที่เห็นในภาพที่ 1-3

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัย ฟารอีสเทอรน


บทที่ 1 เริ่มตนกับ Java

กอนจะถึง Java

7

ในการ execute โปรแกรมนัน ้ เราจะไมใส .class ตามหลังชือ ่ ไฟล (ถึงแมวา เราตองมีไฟลนี้ก็ตาม) ถาเรา ใส compilerก็จะฟองดวย error ที่บอกวา หาไฟลไมเจอ (java.lang.NoClassDefFoundError) ดังที่เห็น นี้

สรุปขั้นตอนของการพัฒนาโปรแกรมที่เปน application 1. compile ดวยคําสั่ง javac ตามดวยชื่อไฟล พรอมกับนามสกุล 2. execute ดวยคําสั่ง java ตามดวยชื่อไฟลโดยไมมีนามสกุลใด ๆ ตอทาย การเขียนโปรแกรมทีด ่ ีนั้น ผูเขียนควรใสคําอธิบาย (comment) ถึงการทํางานของโปรแกรมที่เขียนขึ้น เพื่อใหผท ู ี่นําโปรแกรมไปใช หรือผูอานคนอืน ่ เขาใจถึงวิธีการใชทถ ี่ ูกตอง ในการเขียน comment ดวย ภาษา Java นั้น มีการทําไดสองวิธี คือ 1. การใช // 2. การใช /* … */ การใชในแบบที่หนึ่งนั้น เปนการใส comment ไดไมเกิน 1 บรรทัด สวนการใชในแบบทีส ่ อง ผูใชสามารถ ที่จะใส comment ไดมากกวาหนึ่งบรรทัด แต comment ตองอยูภายในเครือ ่ งหมาย /* … */ เทานั้น ดัง ตัวอยางจากการนําโปรแกรม HelloWorld มาเขียนใหมดวย comment // My first Java program - HelloWorld class HelloWorld { /* Java launcher will call this method (main). This will display a message to the screen. */ public static void main(String[] args) { System.out.println("Hello World"); } } การสรางโปรแกรม Java ทีเ่ ปน applet ในการเขียนโปรแกรมที่เปน Java applet นั้นเราจะตองมีไฟลอยูอยางนอย 2 ไฟล ซึ่งหนึ่งในนั้นคือ Java source file และอีกไฟลหนึ่งคือ HTML file เราลองมาเขียน applet เล็ก ๆ ที่สงขอความไปยัง web browser เหมือนกับที่เราเขียน application กอนหนานี้ //my first Java applet - HelloWorldApplet import java.applet.Applet; import java.awt.Graphics; public class HelloWorldApplet extends Applet { public void paint(Graphics g) { g.drawString("Hello World", 25, 25); } }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัย ฟารอีสเทอรน


บทที่ 1 เริ่มตนกับ Java

กอนจะถึง Java

8

เนื่องจากวาเราตองการ applet สําหรับการสงขอความไปยัง web browser ดังนั้นเราจึงตองดึงเอา เครื่องมือทีช ่ วยใหเราสามารถแสดงขอความทีว่ า ดวยการใชการถายทอดคุณสมบัติ (inheritance) ที่ Java มีใหดวยการเพิ่มคําวา extends Applet ทางดานหลังของ class HelloWorldApplet เราจะยังไมพูด ถึงรายละเอียดเกี่ยวกับการถายทอดคุณสมบัตข ิ อง Java ตอนนี้ อีกสิ่งหนึ่งทีข ่ าดไมไดในการเขียน applet ของเราตอนนี้ก็คือ method paint() ซึ่งเปน method ที่ทาํ การวาดขอความลงบน applet ดวยการเรียกใช method drawstring() จาก class Graphics ในตําแหนงที่กาํ หนดไว จากคําสั่งนี้ g.drawString("Hello World", 25, 25); เมื่อ compile โปรแกรม HelloWorldApplet ดวยคําสั่ง javac แลวเราก็สามารถที่จะ execute applet ได ดวยการเรียก HTML ไฟลที่เขียนขึ้น ดังนี้ <html> <applet code="HelloWorldApplet.class" width="200" height="80"></applet> </html> ดวยการใช applet tag ใน HTML ไฟลพรอมกับการใสชื่อของ Java ไฟลที่ compile แลวในสวนของ field ที่ชื่อ code และกําหนดขนาดความกวางของ applet ใน field ที่ชื่อ width และความยาว (สูง) ใน field ที่ชื่อ height การ execute ไฟล HelloWorldApplet.html ก็สามารถทําไดดวยการใชคําสัง่ appletviewer ตามดวยชื่อ ไฟล เราก็จะได output ดังนี้

สรุปขั้นตอนการเขียนโปรแกรมแบบ applet 1. สราง Java source file ดวยการ extends Applet 2. สราง HTML file ที่มี applet tag และขอมูลที่สาํ คัญในการแสดง applet คือ (1) class file ของ Java โปรแกรม (2) ขนาดของ applet – width และ height เราจะกลับมาดูวิธีการเขียน applet อีกครั้งหนึง่ หลังจากที่เรา ไดศึกษาถึงโครงสรางตาง ๆ ของภาษา Java ขั้นตอนการออกแบบ และการเรียกใช class รวมไปถึงเทคนิคและวิธีการใช method ตาง ๆ ที่ Java มีให การเขียน Java program ดวย EditPlus ตัวอยางของโปรแกรม HelloWorld.java ที่เราไดเขียนขึ้นกอนหนานี้ใชภาษาอังกฤษทั้งหมดในการเขียน ผลลัพธที่ไดจากการ run โปรแกรมก็เปนภาษาอังกฤษ ผานทาง Dos Window ถาเราตองการที่จะเขียน โปรแกรมเพื่อใหแสดงผลลัพธ หรือ ขอความที่เปนภาษาไทยนั้น จะตองใช Operating System ที่รองรับ การปอนและสงขอมูลที่เปนภาษาไทย เชน Windows ตาง ๆ ที่สรางขึ้นมาเพือ ่ คนไทยโดยเฉพาะ ซึ่งจะ สังเกตไดจากคําวา Thai Edition หรือ คําวา ไทย ตอทาย แตก็มี OS หลาย ๆ ตัวทีย ่ อมใหมีการปอนและ สงขอมูลที่เปนภาษาไทยผานทางชองทางอืน ่ ๆ ที่ไมใช Dos Window ในการฝกฝนการเขียนโปรแกรม Java ใหม ๆ นั้นเราจําเปนทีจ ่ ะตองมีชองทางในการแสดงผลทีส ่ ามารถใชไดทั้งภาษาไทย และ ภาษาอังกฤษ ดังนั้นเพื่อใหการปอนและสงขอมูลใชไดทั้งภาษาไทยและภาษาอังกฤษ เราจะเลือกใช Text Editor ที่รองรับภาษาไทย เชน EditPlus (มี Text Editor หลายตัวทีร่ องรับภาษาไทย แตเราจะพูด ถึงเฉพาะ EditPlus เทานั้น)

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัย ฟารอีสเทอรน


บทที่ 1 เริ่มตนกับ Java

กอนจะถึง Java

9

กอนอื่นเราตองหา EditPlus มาติดตั้งในเครื่องที่เราใชในการสรางโปรแกรมดวยภาษา Java เสียกอน ซึ่ง สามารถที่จะไป download มาไดจาก www.editplus.com โปรแกรมตัวนี้เปน shareware ที่มีอายุการใช งานเพียงแค 30 วันหลังจากนัน ้ ก็คงตองควักกระเปาจายใหกับเจาของโปรแกรมตามระเบียบ ซึ่งก็ไมแพง เทาไรนัก เมื่อ install เรียบรอยแลวก็ใหเขาไปใน menu ที่ชอ ื่ วา Tools

เลือก Preferences

click ที่ Fonts และเลือก Default (edit window) จาก Drop-down menu ในชองทีช ่ ื่อ Area เสร็จแลว ใหเลือก font ที่สามารถใชภาษาไทยได เชน Tahoma ดังทีเ่ ห็นในรูป เสร็จแลวก็เริ่มทําในลักษณะ เดียวกันกับ Output window

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัย ฟารอีสเทอรน


บทที่ 1 เริ่มตนกับ Java

กอนจะถึง Java

10

หลังจากที่ set คาใหกับ editor และ output window เรียบรอยแลว เราก็ตอ  งมา set ให EditPlus รูจัก กับการ compile และ execute โปรแกรมในภาษา Java เริ่มตนดวยการ click ที่ User tools ใน Preferences และกดปุม Add Tool>> เพื่อเลือก Program

เสร็จแลวใหใสขอมูลดังตัวอยางที่เห็น Menu Text: Command: Argument: Initial directory:

Compile Java Source File

ที่ทผ ี่ ูอานได install Java ไว เชน c:\j2sdk1.4.1\bin\javac.exe $(FileName) เลือกจาก drop-down list $(FileDir) เลือกจาก drop-down list

พรอมกับใสเครือ ่ งหมาย 9 ในชอง Capture output

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัย ฟารอีสเทอรน


บทที่ 1 เริ่มตนกับ Java

กอนจะถึง Java

11

เสร็จแลวใหเพิ่มคําสั่งให EditPlus รูจักการ run หรือ execute โปรแกรมทีไ ่ ด compile เรียบรอยแลว ดวยการกดปุม Add tool>> อีกครั้งหนึ่ง พรอมกับใสขอมูลทีเ่ ห็นนี้

เมื่อทําทุกอยางเรียบรอยแลวใหกดปุม OK เพื่อทําการบันทึกคําสั่งที่เราสรางขึ้นให EditPlus รูจัก และเมื่อไดเปลีย ่ นแปลงไฟล HelloWorld.java ดวยการเพิม ่ ขอความที่เปนภาษาไทยเขาไปในประโยค System.out.println(…) เชนในตัวอยางนี้ class HelloWorld { public static void main(String[] args) { System.out.println("Hello World! สวัสดีครับ โลกเกา ๆ ใบนี้"); } } เราก็ compile ดวยการกด Ctrl + 1 และเมื่อ compile เสร็จเราก็จะไดรับขอความดังที่เห็นนี้

หลังจากนั้นเราก็ run ดวยการกด Ctrl + 2 ก็จะไดผลลัพธดงั ที่เห็นนี้

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัย ฟารอีสเทอรน


บทที่ 1 เริ่มตนกับ Java

กอนจะถึง Java

12

EditPlus ยังมี features ตาง ๆ อีกมากมายที่เราสามารถที่จะ set ไวชวยในการทํางานของเราได ทั้งนี้ ผูอานสามารถที่จะหาขอมูลเพิ่มเติมไดจาก help file ของตัว EditPlus เอง แตถาผูอานอยากใช Text Editor ตัวอื่นผูเ ขียนขอแนะนําอีกตัวหนึ่งคือ Crimson ซึ่งเปน editor ที่ไมตองเสียคาใชจา ยใด ๆ เลย และสามารถที่จะ download ไดจากหลาย ๆ ที่ใน WWW ที่มาของภาษา Java โดยสังเขป Java เปนภาษาที่เกิดขึ้นจากการพัฒนาของบริษัท Sun Microsystems โดยมีที่มาจากภาษาทีช ่ ื่อวา Oak ซึ่งเปนภาษาทีใ่ ชภายใน Sun เองแตหลังจากที่ Sun ไดพัฒนา Oak และใชมาอีกระยะหนึง่ Sun ก็ได นําเอา Oak ออกมาสูส  ายตาชาวบานทัว่ ไป แตเนื่องจากวา ชื่อของ Oak ไดมีผใู ชอยูกอนแลว Sun จึง ตองหาชื่อใหมใหกับภาษานี้ ซึ่งในตอนแรกก็ไดทดลองหลายชื่อ เชน Silk, Ruby, และ WRL (Web Runner Language) แตชื่อเหลานี้ก็ไมไดถก ู เลือก ในที่สด ุ Java ก็กลายเปนชื่อของภาษานี้ (ทั้ง ๆ ที่ไมมี อะไรเกี่ยวของกับ กาแฟ จาก ชวา หรืออะไรที่เกี่ยวของกับเกาะชวาเลย) Java มีอยูมากมายหลาย version แต version ลาสุดของ Java ขณะที่เขียนตําราเลมนี้ คือ J2SDK1.4.1 ผูอานสามารถติดตาม version ใหม ๆ และ download ไดที่ web site ของ Sun ที่ไดใหไวกอนหนานี้ ในบททีส ่ องเราจะมาทําความรูจ  ักกับขอกําหนด ตาง ๆ ของ โปรแกรม ขอมูล (data) ตัวแปร (variable) และ การประมวลผล (calculation – evaluation)

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัย ฟารอีสเทอรน


ในบททีส ่ องนี้เราจะมาทําความเขาใจในเรื่องของชนิดขอมูลที่ Java มีไวในการรองรับการเขียนโปรแกรม ทั้งขอมูลที่เปนตัวเลข และขอมูลที่เปนตัวอักษร เราจะทดลองเขียนโปรแกรมดวยขอมูลชนิดตาง ๆ นี้ หลังจากจบบทเรียนนี้แลว ผูอา นจะไดทราบถึง o o o o o o o

วิธีการประกาศตัวแปร (variable declaration) ที่มีชนิดเปน integer และ floating-point วิธีการประกาศตัวแปรที่มช ี นิดเปน character และ boolean วิธีการกําหนด (assignment) คาใหกับตัวแปรตาง ๆ การสรางประโยค (statement หรือ expression) การประมวลผล (calculation และ evaluation) ที่เกี่ยวกับตัวแปรชนิดตาง ๆ การเปลี่ยนแปลง (casting) ชนิดของขอมูล การใชฟงคชั่นทางคณิตศาสตร (Mathematical Functions) ที่ Java มีให

ขอมูล และ ตัวแปร (data and variable) โดยทั่วไปถาเราตองการคํานวณหาคาทางคณิตศาสตร เชน 354 + 45 * 12 เรามักจะใชเครื่องคิดเลข หรือไมก็ใชวิธค ี ด ิ ในกระดาษ ซึง่ วิธีคิดแบบทีส ่ องนี้เราใชกระดาษเปนตัวกลางในการหาคานั้น ๆ กลาวคือ เราใชกระดาษเปนที่เก็บตัวเลขที่ตองการหาคา รวมไปถึงผลลัพธของการหาคานั้น ๆ ดวย เชนเดียวกับ การเขียนโปรแกรมทางคอมพิวเตอร คาตาง ๆ เหลานี้จําเปนจะตองมีที่เก็บ และที่เก็บขอมูลเหลานี้ตอง เปนที่เก็บที่สามารถรองรับการประมวลผล หรือ การคํานวณไดอยางพอเพียง ดังนั้นในการเขียนโปรแกรม เราจึงตองใชตัวแปรเปนที่เก็บขอมูลตาง ๆ ที่เราจะตองใชในการประมวลผล ตัวแปรที่วา นี้เปนสัญลักษณแทนหนวยความจํา (memory) ที่อยูในเครื่อง และ compiler จะเปนผูกําหนด วาอยูทใี่ ด มีขนาดเทาใด (address เริ่มตน และ offset) ที่เก็บขอมูลนี้จะเก็บขอมูลไดเพียงชนิดที่เราได กําหนดไว เพียงชนิดเดียวเทานั้น ขอมูลถูกแบงออกตามชนิดของขอมูล หลัก ๆ คือ ขอมูลที่เปนตัวเลข และ ขอมูลที่ไมใชตวั เลข แตจะแบงยอย ๆ ลงไปอีก เชน ถาเรากําหนดใหตัวแปรตัวใดตัวหนึ่งเก็บขอมูล ชนิดที่เปนตัวเลขในแบบของ integer เราก็ไมสามารถที่จะนําเอาขอมูลที่เปนตัวเลขในรูปแบบอื่น เชน double หรือ float มาเก็บไวในตัวแปรนี้ได เนื่องจากวาขอมูลที่ตวั แปรเก็บไดนั้นมีขนาดตายตัว ตามการ ออกแบบของภาษา ดังนั้น การนําเอาขอมูลชนิดอื่นมาใสไวในตัวแปรนี้จะถูกตรวจสอบโดย compiler และ compiler จะฟองไปยังผูเขียนโปรแกรมทันที การประกาศตัวแปรนั้น ผูเขียนโปรแกรมจะใชสัญลักษณใด ๆ ก็ไดที่ Java ยอมใหใช ซึ่งตองอยูใน กฎเกณฑ ตอไปนี้ 1. ตองขึ้นตนดวยตัวอักษร (letter) หรือ เครื่องหมาย _ (underscore) หรือ เครื่องหมาย $ (dollar sign) 2. เครื่องหมายอื่น ๆ ที่ตามมาเปนไดทั้ง ตัวอักษร ตัวเลข และ สัญลักษณอื่น ๆ ที่ไมไดถูกใชโดย Java (เชน operator ตาง ๆ ที่ Java ใชดังตัวอยางของการ + (บวก) – (ลบ) * (คูณ) / (หาร) เปนตน) ตัวอยางของตัวแปรที่ถูกตอง taxRate pricePerUnit


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

14

_timeInSecond $systemClock unit897 เนื่องจากวา Java ไดออกแบบใหผใู ชสามารถที่จะกําหนดตัวแปรใหเปน Unicode1 เพื่อเปดโอกาสใหการ ออกแบบตัวแปรเปนไปไดในภาษานั้น ๆ ของ ผูเขียนโปรแกรม เราจึงสามารถทีจ ่ ะใชตัวแปรที่เปน ภาษาไทยได สิ่งที่เราตองคํานึงถึงก็คือ text editor ที่เราใชในการเขียน code ตองยอมใหเราใช ภาษาไทยดวย ในบทนีแ ้ ละบทอื่น ๆ ของตํารานี้จะใชตัวแปรที่เปนภาษาอังกฤษเทานั้น เพือ ่ ใหงายตอการ เขียน และการทําความเขาใจในเนื้อหาไดรวดเร็วขึ้น โดยทั่วไปเราจะเรียกตัวแปรทีไ ่ ดกําหนดใหเก็บขอมูลชนิดใด ชนิดหนึ่งวา variable หรือ identifier และ identifier ที่วานี้ มีความยาวเทาไรก็ได (จํานวนของตัวอักษร) แตกต ็ องอยูภายใตขอกําหนดที่ไดกลาว มาแลว พรอมกันนี้ ตัวแปรทีส ่ รางขึ้นจะตองไมใช keyword หรือ reserved word ที่ Java ไดสรางขึ้นไว ใชงาน ดังที่แสดงในตาราง 2.1 ตารางที่ 2.1 keyword abstract const boolean continue break default byte do case double catch else char extends class final

finally float for goto if implements import instanceof

int interface long native new package private protected

public return short static strictfp super switch synchronized

this throws throws transient try void volatile while

ชนิดของขอมูล (datatype) ในการประกาศตัวแปรทุกครั้งเราจะตองบอกชนิดของขอมูลใหกับ ตัวแปรนัน ้ ดวย ซึ่งการประกาศตัวแปร นั้น ตองเริ่มตนดวย ชนิดของขอมูล และตามดวย ชื่อของตัวแปร ตามรูปแบบที่กําหนดดังนี้

datatype identifier โดยที่ datatype คือชนิดของขอมูลที่ ตัวแปรสามารถเก็บได และในภาษา Java datatype เปนไดทั้ง ขอมูลที่เรียกวา primitive datatype และขอมูลที่เปน reference (เราจะพูดถึง reference ในบทอื่น) Java กําหนดใหมี primitive datatype จํานวนทั้งสิ้น 8 ชนิด ดังที่แสดงใหเห็นในตารางที่ 2.2 ตาราง 2.2 primitive datatype boolean byte short int long float double char

datatype คําอธิบาย คาทางตรรกะ ตัวเลขที่ไมมจ ี ด ุ ทศนิยม ตัวเลขที่ไมมจ ี ด ุ ทศนิยม ตัวเลขที่ไมมจ ี ด ุ ทศนิยม ตัวเลขที่ไมมจ ี ด ุ ทศนิยม ตัวเลขที่มจ ี ุดทศนิยม ตัวเลขที่มจ ี ุดทศนิยม ตัวอักษร

ขนาด (bit) 8 มีคาเปน true หรือ false 8 16 32 64 32 64 16

ขนาดของ datatype จะเปนตัวกําหนดคาที่เราสามารถเก็บไดในตัวแปรที่ไดประกาศในโปรแกรม ยิ่ง จํานวนของ bit มากเทาไรเราก็สามารถเก็บคาสูง ๆ ได ตารางที่ 2.3 แสดงคาตาง ๆ ที่สามารถเก็บไดใน datatype ชนิดตาง ๆ

1

มีความจุ 2 byte เพื่อรองรับภาษาที่ใชกันในประเทศตาง ๆ (เดิมใช ASCII ซึ่งมีความจุเพียง 1 byte)

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

ตาราง 2.3 คาที่เก็บไดใน primitive datatype ตาง ๆ datatype คาต่า ํ สุด byte -128 short -32768 int -2147483648 long -9223372036854775808 float -3.4 x 1038 double -1.7 x 10308

15

คาสูงสุด 127 32767 2147483647 9223372036854775807 3.4 x 1038 1.7 x 10308

ตัวอยางการประกาศตัวแปร int numberOfBikes; float taxRate; double interests, PI; boolean yesOrNo; char response; โดยทั่วไปนักพัฒนาโปรแกรมมักจะใช ตัวอักษรตัวเล็กเปนตัวเริ่มตนของตัวแปร และจะเปลี่ยนเปนอักษร ตัวใหญเมื่อคํานั้น ๆ สิ้นสุดลง เชนการประกาศตัวแปรที่เห็นดานบนนี้ อีกวิธีหนึ่งที่หลาย ๆ คนชอบใช คือ การใชเครื่องหมาย _ (underscore) เปนตัวแบงคํา เชน int number_of_bikes; float tax_rate; double cum_gpa; boolean yes_or_no; ทั้งนี้และทั้งนั้น การประกาศตัวแปรทั้งสองวิธท ี ําใหการอานตัวแปรทําไดงายขึ้น แตสิ่งสําคัญที่เราจําเปน จะตองคํานึงถึงในการประกาศตัวแปรก็คือ การเลือกใชคาํ ทีส ่ อ ื่ ถึงความหมายของขอมูลที่ตวั แปรนั้น ๆ รองรับ หรือ เก็บอยู เชน ถาเราตองการเก็บขอมูลที่เปนเกรดที่เปนตัวอักษร เราก็ควรใช ตัวแปรที่สื่อถึง เกรดที่เปนตัวอักษร เชน คําวา letterGrade และถาเราตองการเก็บเกรดที่เปนคาเฉลีย ่ เราก็ควรใช ตัวแปร เชน gpa หรือ cumulativeGPA เปนตน การกําหนดคาใหกับตัวแปร (Assignment) การกําหนดคาใหกับตัวแปรนั้นทําไดดวยการใชเครื่องหมาย = (เรียกกันวา assignment operator) ซึ่งมี ความหมายวา "ใหนําคาทางขวามือ (rvalue) ของเครื่องหมาย = ไปเก็บไวในตัวแปรที่อยูท  างดาน ซายมือ (lvalue) ของเครื่องหมาย =" rvalue สามารถเปนไดทั้ง คาคงที่ ตัวแปร หรือประโยคใด ๆ ที่ สามารถหาคาได สวน lvalue เปนไดเฉพาะตัวแปรเทานั้น เพราะจะตองเปนที่ที่เก็บขอมูลได (physical memory) เชน numberOfBikes = 2; area = PI * r * r; taxReturned = calculateTaxReturned(income); แตไมใชแบบนี้ 2 = numberOfBikes; PI * r * r = area; calculateTaxReturned(income) = taxReturned; ในการกําหนดคาใหกับตัวแปรนั้น ถาเรามองในมุมมองของที่มาของคาที่นาํ มาใสใหกับตัวแปร เราก็ สามารถที่จะแบงการกําหนดคาไดเปนสองแบบ คือ (1) การกําหนดคาใหกบ ั ตัวแปรภายในตัวโปรแกรม และ (2) การกําหนดคาใหกับตัวแปรผานทางสื่อการนําเขาขอมูลมาตรฐาน (standard I/O channel) เรา จะมาทําความเขาใจการกําหนดคาในแบบที่หนึ่งกันกอน เพราะเปนการกําหนดคาที่งายทีส ่ ด ุ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

16

การกําหนดคาใหกับตัวแปรภายในโปรแกรม การกําหนดคาใหกับตัวแปรนั้นสําคัญมาก เพราะโดยทั่วไปตัวแปรจะไมมีคาใด ๆ เลยหลังจากการประกาศ ภาษาในการเขียนโปรแกรมหลาย ๆ ภาษาบังคับใหผูเขียนโปรแกรมกําหนดคาเบื้องตน กอนที่จะใชตวั แปรนั้น ๆ ซึ่งก็เปนสิ่งทีด ่ ี เพราะจะทําใหการเขียนโปรแกรมเปนไปไดงาย และสะดวกตอการตรวจสอบ หากมีขอผิดพลาดเกิดขึ้น โปรแกรมตัวอยางที่เห็นนี้แสดงถึงวิธีการประกาศตัวแปรพรอมกับการกําหนดคา เบื้องตนใหกับตัวแปรเหลานั้น /* * Variables.java - Variable decalration and initialization */ class Variables { public static void main(String[] args) { boolean booleanVar = true; byte byteVar = 0; short shortVar = 0; int intVar = 0; long longVar = 0L; float floatVar = 0.0F; double doubleVar = 0.0D; char charVar = 'A';

}

}

System.out.println("boolean variable and its initial value is " + booleanVar); System.out.println("byte variable and its initial value is " + byteVar); System.out.println("short variable and its initial value is " + shortVar); System.out.println("int variable and its initial value is " + intVar); System.out.println("long variable and its initial value is " + longVar); System.out.println("float variable and its initial value is " + floatVar); System.out.println("double variable and its initial value is " + doubleVar); System.out.println("char variable and its initial value is " + charVar);

เรากําหนดคาทีเ่ ปนศูนยใหกับตัวแปรทุกตัว ยกเวนตัวแปรที่เปน boolean ซึ่งเรากําหนดคาใหเปน true เราบอกให Java รูวาคาที่กําหนดใหกับตัวแปรตาง ๆ มีชนิดเปนอะไรไดดวยการใสตัวอักษรที่บงบอกชนิด นั้น ๆ ของตัวแปร เชน 0L 0.0F และ 0.0D ซึง่ หมายถึง คาของศูนยที่เปน long คาของศูนยที่เปน float และ คาของศูนยที่เปน double ตามลําดับ ทัง้ นี้เพื่อบอกให Java รูวาเราตองการใชคาที่เก็บชนิดนั้น ๆ จริง ซึ่งเราจําเปนที่จะตองทําเพียงคาของตัวแปรที่เปน float และ double เทานั้น เพราะวาตัวแปรทีม ่ ี ชนิดเปน float ถามีการกําหนดคา Java จะเหมาเอาวาเปน double เราจึงตองกําหนดคาตามชนิดของตัว แปรจริง ๆ ที่เราตองการ ผลลัพธของโปรแกรม Variables.java boolean variable and its initial value is true byte variable and its initial value is 0 short variable and its initial value is 0 int variable and its initial value is 0 long variable and its initial value is 0

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

17

float variable and its initial value is 0.0 double variable and its initial value is 0.0 char variable and its initial value is A เรามาดูขั้นตอนที่ Java เก็บขอมูลในตัวแปรกันดีกวา (หากจะบอกวาภาษาอื่น ๆ ก็เก็บแบบนี้ก็คงจะไมผด ิ นัก) เราจะใชตวั แปรจากโปรแกรมตัวอยางขางบน จากประโยคของการประกาศและกําหนดคา long longVar = 0L; ประโยคที่เห็นดานบนนี้สามารถที่จะเขียนไดอีกแบบหนึ่งคือ long longVar; longVar = 0L; ประโยค long longVar; นั้นเปนการประกาศตัวแปรชื่อ longVar ที่มีชนิดเปน long สวนประโยค longVar = 0L; นั้นเปนการกําหนดคา 0 ใหกับตัวแปร longVar (ภาพที่ 2.1 แสดงถึงขั้นตอนในการสรางตัวแปร และการกําหนดคาใหกับตัวแปรของ Java) การประกาศพรอมกับกําหนดคาใหกับตัวแปรในประโยค เดียวกัน ชวยใหการเขียน code เมื่อมองดูแลวสวยและกะทัดรัดขึ้น ทั้งนีก ้ ็คงจะขึ้นอยูกบ ั ตัวผูอานเองวามี ความคิดเห็นอยางไร สําหรับตัวผูเขียนเองคิดวาถาเปนการประกาศที่มต ี ัวแปรไมกี่ตัวในบรรทัดนั้นก็คง มองดูแลวสวยดี แตถามีมากเกินไปก็คงจะไมเขาทาเทาไรนัก ตัวอยางเชน double price = 0.0D, tax = 0.7D, returned = 0.0D, interests = 0.0D, principal = 10000.0D; โปรแกรมเมอรควรจะแยกการประกาศที่เห็นดานบนนี้ใหอยูค  นละบรรทัดเพื่อใหงายตอการอาน และ เปลี่ยนแปลง หากมีการเปลี่ยนแปลงเกิดขึ้นในโปรแกรม

long longVar;

longVar = 0L;

???

0

ประกาศตัวแปรชนิด long ชื่อวา longVar ซึ่ง Java จะจอง หนวยความจําใหแตไมมีคาใด ๆ ณ หนวยความจํานั้น

หลังจากกําหนดคา 0 ใหกับ longVar แลวหนวยความจํา ณ ตําแหนงนั้นก็จะมีคาตามที่ กําหนดให คือ 0

ภาพที่ 2.1 การกําหนดคาใหกับตัวแปร

ในการกําหนดคาใหกับตัวแปรนั้น เราไมจําเปนที่จะตองกําหนดคาของตัวแปรตาง ๆ ใหเปนศูนย เรา สามารถที่จะกําหนดคาอะไร ก็ไดใหกับตัวแปรเหลานี้ ทั้งนี้ขน ึ้ อยูกับการใชงานของตัวแปรนั้น ๆ หลาย ๆ ครั้งที่เราตองตัดสินใจวาควรจะใชตัวแปรชนิดใดดี ในกรณีทข ี่ อมูลเปนชนิดที่อยูในหมวดเดียวกัน เชน ขอมูลเปนเลขที่ไมมีจด ุ ทศนิยม หรือ ขอมูลเปนเลขที่มีจด ุ ทศนิยม ซึ่งถาเหตุการณเหลานี้เกิดขึ้น เราก็ จําเปนที่จะตองคิดถึงคาความเปนไปไดของขอมูลวาอยูใน range เทาใด เชน ถาเราตองการใชตัวแปร รองรับขอมูลที่เปนเลขที่ไมมีจด ุ ทศนิยมที่มีขนาดไมเกิน 127 เราก็ควรที่จะประกาศตัวแปรดวยการใช byte แทนการใช int เปนตน เราสามารถทีจ ่ ะประกาศตัวแปรพรอมกับการกําหนดคาใหกับตัวแปร หลาย ๆ ตัวในหนึ่งประโยค เชน int length = 2, height = 8, width = 4; double angles = 30.5, distance = 24.50;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

18

การประกาศตัวแปรในรูปแบบนี้ตองใชเครื่องหมาย , (comma) เปนตัวแบงตัวแปรออกจากกัน และตัวแปร เหลานั้นจะมีชนิดเปนชนิดเดียวกันตลอด เราไมสามารถประกาศตัวแปรตางชนิดกันไดดวยวิธีการประกาศ แบบนี้ เชน int cats = 90, float tax = 0.50; // ERROR – mixed-type declaration // and initialization การประกาศตัวแปรไมจําเปนตองกําหนดคาใหทันที แตสามารถที่จะกําหนดไดภายหลัง เชน double radius; radius = 2.54; ลองมาดูการประกาศและกําหนดคาในรูปแบบอีกรูปแบบหนึง่ int one = 1, two = 2, three = one + two; Java ยอมใหมก ี ารประกาศและกําหนดคาแบบนี้ได เนื่องจากวา ตัวแปร one และ two มีการกําหนดคา เรียบรอยแลว ดังนั้น การประกาศและกําหนดคาใหกับตัวแปร three จึงทําไดโดยไมมป ี ญ  หาใด ๆ จาก compiler เลย ประโยค three = one + two; เปนประโยคทีม ่ ีการประมวลผลของ one + two กอนแลว จึงนําคาที่ไดมาเก็บไวที่ตัวแปร three เราจะพูดถึง ประโยค และ การประมวลผลที่เกิดขึ้นในประโยคใน โอกาสตอไป การใช final ในการกําหนดคาใหกับตัวแปร หลาย ๆ ครั้งที่เราตองการใชคา บางคาตลอดอายุการทํางานของโปรแกรม เชน คาของ PI หรือ คาคงทีท ่ ี่ จะไมมีการเปลีย ่ นแปลงใด ๆ ในขณะใชงานในโปรแกรม Java มีคําสั่งที่ user ไมสามารถที่นํามาใชในการ ประกาศตัวแปรได (reserved word) แตเอาไวใชในงานนี้โดยเฉพาะ คือ คําวา final ถาเราขึ้นตนการประกาศตัวแปรดวยคําวา final ตัวแปรนั้น ๆ จะไมสามารถมีคาอื่น ๆ ไดอีก ไมวาจะเปน การเปลี่ยนคาภายในโปรแกรม หรือ การเปลี่ยนแปลงที่เกิดจากการใสขอมูลใหมผานทาง keyboard ดัง โปรแกรมตัวอยางที่แสดงใหเห็นนี้ /* * Final.java - Use of final keyword */ class Final { public static void main(String[] args) { final double PI = 3.14; int radius = 2;

}

}

double area = radius * radius * PI; System.out.println("Area of a circle is " + area);

หลังจากที่ compile และ run โปรแกรม ผลลัพธที่ไดคือ Area of a circle is 12.56 ถาเราเปลีย ่ นแปลงโปรแกรม Final.java ดวยการกําหนดคาใหกับตัวแปร PI ใหม ดังที่เห็นในโปรแกรม FinalWithError.java นี้ compiler จะฟองดวยขอมูลดังที่เห็น /* * FinalWithError.java - Changing the value of final keyword */

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

19

class FinalWithError { public static void main(String[] args) { final double PI = 3.14; int radius = 2; double area = radius * radius * PI; System.out.println("Area of a circle is " + area);

}

}

PI = 3.142; area = radius * radius * PI; System.out.println("Area of a circle is " + area);

ผลของการ compile FinalWithError.java:14: cannot assign a value to final variable PI PI = 3.142; ^ 1 error ขออธิบายถึงขอความ error ที่ Java ฟองสักนิดหนอย ถาผูอานสังเกต error ที่เกิดขึ้นจะเห็นเลข 14 ถัด จากชื่อของโปรแกรมที่ไดรับการ compile ซึ่งบงบอกถึงเลขที่บรรทัดที่ error นี้เกิดขึ้น รวมไปถึงตําแหนง ที่ error เกิดขึ้นซึ่งเปนตัวชวยใหเรากลับเขาไปแกไขโปรแกรมของเราไดงายยิ่งขึ้น (ไมตองเสียเวลา คนหาบรรทัดทีเ่ กิด error) การใช final ทําใหโปรแกรมมีความแมนยําและมั่นคงมากยิ่งขึ้น ความพยายามที่จะเปลี่ยนคาเหลานี้ก็ไม สามารถทําได ทําใหการออกแบบและพัฒนาโปรแกรมเปนไปไดดวยดี ลดขอผิดพลาดทีอ ่ าจเกิดขึ้นจาก ตัวโปรแกรมเมอรเอง ในบางครั้งการประกาศตัวแปรตองการใชคาทีส ่ ูงมาก ๆ หรือ คาที่เล็กมาก ๆ เชน ระยะทางจากโลกไปยัง ดวงอาทิตย ซึ่งมีคาโดยประมาณเทากับ 149, 600,000 กิโลเมตร (1.496 x 108) หรือ การกําหนดคาของ มวลของอิเลคตรอน (electron mass) ซึ่งมีคาเล็กมาก ขนาดของมวลโดยประมาณมีคาเทากับ 0.0000000000000000000000000009 กรัม (9.0 x 10-28) เราก็สามารถทําไดดวยการใชการประกาศใน รูปแบบของการกําหนดคาทางวิทยาศาสตร (scientific notation) เชน final double sunDistance = 1.496E8; // 1.496 x 108 final float electronMass = 9.0E-28F; // 9.0 x 10-28 การประกาศและกําหนดคาในรูปแบบนี้ทําใหการมองเห็น และ การเขียนหรือการอานทําไดงา ยยิ่งขึ้น ลอง นึกถึงการที่เราตองเขียนประโยคในการกําหนดคาใหกับ มวลของอิเลคตรอน ที่ไดกลาวถึงขางตนซึ่งมี ศูนยถึง 27 ตัววานารําคาญขนาดไหน (โปรแกรมเมอรสวนใหญรูเรื่องนีด ้ ี) ยิ่งถาเราเขียน code เยอะ ๆ การกําหนดคาใหกับตัวแปรเหลานี้ดวยการเขียนทีส ่ ั้นที่สด ุ ยอมเปนการดีเสมอ (เขียนโปรแกรมไดไวขึ้น?) อายุ และ ขอบเขตการใชงาน (life-time and scope) ของตัวแปร หลังจากที่มีการประกาศใชตัวแปรใด ๆ ในโปรแกรม ตัวแปรเหลานี้จะมีขอบเขต หรืออายุการใชงานตาม ลักษณะการประกาศตัวแปรของผูเขียนโปรแกรมเอง โดยทั่วไปตัวแปรจะมีอายุการใชงานตามเนื้อที่ (block) ที่ตัวแปรเหลานั้นปรากฏอยู ซึ่งจะอยูใ นเครื่องหมาย {} เชนโปรแกรมตัวอยางตอไปนี้ /* Scope.java - Showing scope of variables */ class Scope { public static void main(String[] args) { int x = 5, y = 8;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

20

System.out.print("Value of x is "); System.out.println(" Value of y is " + y); {

}

}

int x = 45; //error x is already defined int w = 89; System.out.println("Value of x in brackets is " + x); System.out.println("Value of y in brackets is " + y);

} //error w is out of scope System.out.println("Value of w is " + w);

เปนที่แนนอนอยูแลววาโปรแกรม Scope.java จะ compile ไมผาน เนื่องจากเหตุผลสองอยางดังที่ compiler ฟอง คือ (1) ตัวแปร int x ไดมีการประกาศใน main() แลว และ (2) ตัวแปร int w ไมไดอยูใน scope ของมันเอง ซึ่งในที่นค ี้ อ ื block ที่มีการประการ int x และ int w Scope.java:13 x is already defined in main(java.lang.String[]) int x = 45; ^ Scope.java:19: cannot resolve symbol symbol : variable w location: class Scope System.out.println("Value of w is " + w); ^ 2 errors ในภาษาอื่น เชน C++ การประกาศตัวแปรใน block ใหมดวยตัวแปรที่มีชื่อซ้ํากันสามารถทําไดโดยไมมี เงื่อนไขใด ๆ (ดังที่เห็นในโปรแกรม Scope.java) แตตวั Java เองไมยอมใหมีการประกาศตัวแปรซ้ํา ถึงแมวาจะอยูใ น block ใหมทซ ี่ อนกันอยูก็ตาม ลองมาดูโปรแกรมตัวอยางอีกตัวหนึ่ง /* Scope2.java - Showing scope of variables */ class Scope2 { static int x = 8, y; public static void main(String[] args) { { int x; x = 5; y = x; System.out.println("Value of y is " + y); } y = x; System.out.println("Value of y is " + y); } }

โปรแกรม Scope2.java หลังจากที่ compile ผานแลวจะไดผลลัพธดังนี้ Value of y is 5 Value of y is 8 จะเห็นวา compiler ยอมใหผา นทั้งนี้เพราะตัวแปร x ใน block ดานในมีการประกาศและกําหนดคาอยาง สมบรูณ และ ตัวแปร x ใน scope ดานนอกมีการกําหนดใหเปน static ซึ่งเปนตัวแปรที่ Java เรียกวา class variable ดังนั้นตัวแปรทัง้ สองจึงไมใชตวั แปรเดียวกัน เพราะฉะนั้นการกําหนดคาใหกบ ั ตัวแปร y ใน

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

21

block ดานในจะไดคาของตัวแปร x ที่อยูดานใน และการกําหนดคาใหกับ y อีกครั้งดานนอกจึงไดคาของ class variable ที่ชื่อวา x เรามาลองดูโปรแกรมตัวอยางอีกโปรแกรมหนึ่ง /* Scope2v1.java - Showing scope of variables */ class Scope2v1 { static int x = 8, y; public static void main(String[] args) { { //int x; x = 5; y = x; System.out.println("Value of y is " + y); } y = x; System.out.println("Value of y is " + y); } } โปรแกรม Scope2v1.java แสดงการใชตัวแปร x ตัวเดียวทีไ ่ ดประกาศกอน method main() ซึ่งมีคาเปน 8 ดังนั้นการเปลี่ยนคาของ x ใน block ดานในทําใหคาของตัวแปร x เปนคาลาสุดคือ 5 ผลลัพธของการ run โปรแกรมนี้จึงไดอยางทีค ่ าดหวังไว คือ Value of y is 5 Value of y is 5 ลองมาดูอีกตัวอยางหนึ่ง /* Scope3.java - Showing scope of variables */ class Scope3 { static int x; public static void main(String[] args) { int x = (x = 12) + 8; System.out.println("Value of local x is " + x); } } ในโปรแกรม Scope3.java นี้เราประกาศตัวแปรสองตัวที่มช ี อ ื่ เหมือนกันคือ x โดยที่ตวั หนึ่งมี scope อยูใน class Scope3 และอีกตัวหนึ่งมี scope อยูใน method main() และเมื่อ compile ผานแลวผลลัพธที่ได คือ Value of local x is 20 คําถามที่เกิดขึน ้ คือ ตัวแปร x ตัวใดที่ Java นํามาใชในการกําหนดคาของประโยค int x = (x = 12) + 8; เพื่อใหเห็นวา Java ใชตัวแปร x ตัวไหนเราจึงดัดแปลง code ใหมโดยกําหนดคาใหกับตัวแปร x ที่อยู ดานนอกใหเปน 4 ดังโปรแกรม Scope3v1.java ที่เห็นนี้ /* Scope3v1.java - Showing scope of variables */ class Scope3v1 { static int x = 4; public static void main(String[] args) { int x = x + 8;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

}

}

ขอมูล ตัวแปร และ การประมวลผล

22

System.out.println("Value of local x is " + x);

และเมื่อ compile เราจึงรูวา Java ใชตัวแปร x ที่อยูใน block ดานในเพราะวา compiler ฟองดวย error Scope3v1.java:8 variable x might not have been initialized int x = x + 8; ^ 1 error เพื่อใหการ compile ผานเราจึงแกไข code ใหมดังที่แสดงใหเห็นในโปรแกรม Scope4.java /* Scope4.java - Showing scope of variables */ class Scope4 { public static void main(String[] args) { int x = (x = 12) + 8; System.out.println("Value of local x is " + x); } } โปรแกรม Scope4.java เปนโปรแกรมเดียวกันกับโปรแกรม Scope3.java เพียงแตเราลบการประกาศตัว แปรที่อยูดา นนอกออก และเมือ ่ compile และ run ผลลัพธที่ไดก็คือผลลัพธเดิมที่ไดจากโปรแกรม Scope3.java แตถา อยากจะใหแนใจวา Java ใชตัวแปรตัวไหนจริง ๆ ก็ลองเปลี่ยน code ใหเปนดังที่เห็น ในโปรแกรม Scope5.java (ถึงตอนนี้ผูอานคงสามารถทายไดวาอะไรจะเกิดขึ้นถามีการ compile) /* Scope5.java - Showing scope of variables */ class Scope5 { public static void main(String[] args) { int x = x + 8; System.out.println("Value of local x is " + x); } } compiler ก็จะฟองดวย error Scope5.java:7: variable x might not have been initialized int x = x + 8; ^ 1 error ซึ่งเปน error ที่เหมือนกันกับ error ที่เกิดขึน ้ จากการ compile โปรแกรม Scope3v1.java (เพราะวาตัว แปร x ยังไมมค ี ากําหนดใด ๆ เลย) ลองมาดูอีกตัวอยางหนึง่ /* Scope6.java - Showing scope of variables */ class Scope6 { public static void main(String[] args) { int x = 12, y = x + 8; System.out.println("Value of local y is " + y); } } ซึ่งไดผลลัพธหลังจากการ compile และ run ดังนี้

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

23

Value of local y is 20 การประกาศและกําหนดคาแบบนี้สามารถทําไดเพราะ x ไดรับการกําหนดคากอนที่จะถูกนํามาใชในการ ประกาศและกําหนดคาใหกับตัวแปร y การประกาศและกําหนดคาใหกับตัวแปรใด ๆ นั้นจะตองคํานึงถึงการใช และขอบเขตของการใชเสมอ ทั้งนี้ ในการกําหนดคาใด ๆ ใหกับตัวแปรนั้นสิ่งทีน ่ ํามากําหนดคานั้นในตัวของมันเองจะตองมีคาอยูแลว หรือ สามารถที่จะทําการประมวลคาไดกอนที่จะนํามาใชในการกําหนดคาใหกับตัวแปรอื่น ดังเชนตัวอยางที่เห็น กอนหนานี้ เราจะมาดูเรื่องของ scope ในสถานะอื่น ๆ เชน scope ของ ตัวแปรที่เกี่ยวของกับ method, class และตัว แปรในสถานะอืน ่ ๆ ที่อยูในเนือ ้ หาที่เราจะไดพูดถึงในบทตอ ๆ ไปเมื่อเราไดพูดถึงเรื่องนั้น ๆ แตจะขอบอก ในที่นี้วา ตัวแปรถูกแบงออกเปน 7 แบบคือ 1. 2. 3. 4. 5. 6. 7.

class variable instance variable array component method parameter constructor parameter exception-handler parameter local variable

แตเราไดพด ู ไปเพียงสองแบบคือ แบบที่ 1 (class variable) และแบบที่ 7 (local variable) การสรางประโยค (statement and expression) ในภาษา Java ประโยค (statement) จะตองจบดวยเครื่องหมาย ; (semicolon) เสมอดังตัวอยางทีแ ่ สดง ใหเห็นนี้ int priceOfBook = 125; float taxReturn; เราไมจําเปนจะตองเขียนประโยคใหจบภายในบรรทัดเดียว แตที่สําคัญตองมีเครื่องหมาย ; ปดทายเสมอ เชน int

priceOfBook = 125 ;

Java จะมองหาเครื่องหมาย ; เสมอโดยไมแยแสวาประโยคนัน ้ ๆ จะกินเนื้อที่กี่บรรทัด แตที่สาํ คัญก็คือ การเขียนทีท ่ ําใหอานไดงาย ยอมจะทําใหทั้งเรา และผูอื่นสามารถที่จะดู code ไดรวดเร็วยิง่ ขึ้น ถาไมเชื่อ ลองดู code จากโปรแกรมนีด ้ ส ู ิ /* Scope2v1.java - Showing scope of variables* @author faa xumsai*/class Scope2v1{static int x = 8, y;public static void main(String[] args) { {int x;x = 5;y = x;System.out.println("Value of y is " + y);}y = x; System.out.println("Value of y is " + y);}} การเขียน code ใหมีรูปแบบที่เหมาะสม อานไดงาย จะทําใหการพัฒนาโปรแกรมเปนไปไดดวยความ รวดเร็วและเปนที่ยอมรับตามระบบสากล รูปแบบที่เหมาะสมนั้นคือมีการยอหนา (indentation) เพื่อใหการ อานทําไดงาย และมองดูแลวสวยงาม ดังโปรแกรมตัวอยางหลาย ๆ ตัวทีแ ่ สดงใหเห็นกอนหนานี้ Expression หมายถึงประโยคในภาษา Java ที่ไดรับการยอมรับวาอยูใ นรูปแบบที่ไดกําหนดไว เชน ประโยคในเรื่องของการกําหนดคาใหกับตัวแปร ประโยคที่ตอ  งมีการประมวลผลในรูปแบบตาง ๆ เชน การ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

24

ประมวลผลทางดานคณิตศาสตร (mathematical evaluation) การประมวลผลทางดานตรรกะ (relational evaluation) เปนตน การประมวลผลทางดานคณิตศาสตรนั้น มี operator ที่ใชอยูด  ังนี้ คือ + (บวก), – (ลบ), * (คูณ), / (หาร) และ % (การหาเศษที่เหลือจากการหารตัวเลขที่เปน integer) โปรแกรมตัวอยางตอไปนี้แสดงถึง การประมวลผลของขอมูลดวย operator ชนิดตาง ๆ ที่ไดกลาวถึง /* Operators.java - Shows mathematical operators */ class Operators { public static void main(String[] args) { int i, j, k; //generate random number between 1 and 10 j = 1 + (int)(Math.random() * 10); k = 1 + (int)(Math.random() * 10); System.out.println("j = " + j + " and k = " + k);

}

//evaluate i = j + k; i = j - k; i = j * k; i = j / k; i = j % k; }

and display results of math System.out.println("j + k = System.out.println("j - k = System.out.println("j * k = System.out.println("j / k = System.out.println("j % k =

operators " + i); " + i); " + i); " + i); " + i);

เนื่องจากวาเราตองการทีจ ่ ะแสดงถึงการสรางประโยคและการประมวลผลดวยคาที่มาจาก ขางในโปรแกรม เอง และเราไดใชเครื่องมือในการสรางคาเหลานี้ใหเราแบบอัตโนมัติ ซึ่งเครื่องมือที่วานี้กค ็ ือ method random() ที่มาจาก class Math (มีอยูใน Java แลว) method random() จะสรางคาระหวาง 0 – 0.9+ พูดงาย ๆก็คือ คาต่ําสุดคือ 0 และคาสูงสุดคือ คาที่ใกล 1 แตไมเทากับ 1 (คา n ใด ๆ ที่อยูในเงื่อนไขนี้ Æ 0.0 <= n < 1.0) เมื่อไดคานี้แลวเราคูณคานี้ดวย 10 แลวบวก 1 เราก็จะไดคา ระหวาง 1 – 10 หลังจากนั้นเราก็คํานวณหาคา i ดวยการใช operator ตาง ๆ พรอมทั้งแสดงคาทีห ่ าไดไปยังหนาจอ และ เมื่อ run โปรแกรมผลลัพธที่ไดคือ j j j j j j

= + * / %

5 k k k k k

and k = 2 = 7 = 3 = 10 = 2 = 1

และเนื่องจากวาเราใช method random() เปนตัวหาคา ดังนั้นการ run ในแตละครั้งก็จะไดผลลัพธที่อาจ ซ้ํากัน หรือแตกตางกัน Operator ตัวอืน ่ ๆ ก็เหมือนกับการคํานวณ ทางดานคณิตศาสตรที่เราคุนเคยโดยทั่วไป ยกเวน % ซึ่งเปน การหาเศษจากการหาร integer ประโยค i = j % k; จะนําเอาคาของตัวแปร k คือ 2 ไปหารคาของตัวแปร j ซึ่งมีคาเปน 5 แลวเก็บเศษที่ไดจากการหารไว (ซึ่งก็คือ 1) เมื่อไดแลวก็นําคานี้ไปเก็บไวในตัวแปร i ตอไป โปรแกรมตัวอยางตอไปนี้แสดงถึงการกําหนดคาดวยขอมูลชนิด int และ double

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

25

/* Operators.java - Shows mathematical operators */ import java.util.Random; class Operators { public static void main(String[] args) { //do the ints int i, j, k; //generate random number between 1 and 10 Random rand = new Random(); j = 1 + rand.nextInt(10); k = 1 + rand.nextInt(10); System.out.println("j = " + j + " and k = " + k); //evaluate i = j + k; i = j - k; i = j * k; i = j / k; i = j % k;

}

}

and display results of math System.out.println("j + k = System.out.println("j - k = System.out.println("j * k = System.out.println("j / k = System.out.println("j % k =

operators " + i); " + i); " + i); " + i); " + i);

//do the doubles double v1, v2, v3; //generate random double between 1.0 and 10.0 (exclusive) v1 = 1.0 + rand.nextDouble() * 9; v2 = 1.0 + rand.nextDouble() * 9; System.out.println("v1 = " + v1 + " v2 = " + v2); v3 = v1 + v2; System.out.println("v1 + v2 = " + v3); v3 = v1 - v2; System.out.println("v1 - v2 = " + v3); v3 = v1 * v2; System.out.println("v1 * v2 = " + v3); v3 = v1 / v2; System.out.println("v1 / v2 = " + v3);

โปรแกรม Operators.java แสดงตัวอยางของการกําหนดคา และ การคํานวณดวย operator อยาง งาย ๆ ทางดานคณิตศาสตร โดยเริ่มตนดวยการกําหนดคาใหกับตัวแปร i และ j ดวยการสรางคาแบบสุม (random) จาก method nextInt(max value) ซึ่ง method นี้จะกําหนดคาที่อยูระหวาง 0 ถึง คาที่ กําหนดใน max value แตไมรวมตัว max value ดวยซึ่งถาเราตองการที่จะสรางคาที่อยูระหวาง 1 ถึง 10 เราก็ตองบวก 1 เขากับคาที่เกิดจากการเรียกใช method นี้ดว ย ดังที่ไดกําหนดไวในโปรแกรม เราสามารถทีจ ่ ะเขียนประโยคที่มีการประมวลผลในรูปของประโยคที่มีหลายตัวแปรในประโยคเดียวกันได ดังตัวอยางนี้ /* Operators1.java - Shows mathematical operators */ class Operators1 { public static void main(String[] args) { int a, b, c, d, e; b c d e

= = = =

1 1 1 1

+ + + +

(int)(Math.random() (int)(Math.random() (int)(Math.random() (int)(Math.random()

* * * *

10); 10); 10); 10);

System.out.print("b = " + b + " c = " + c); System.out.println(" d = " + d + " e = " + e); a = b + c - d; System.out.println("Value of a is " + a); a = b * c - d; System.out.println("Value of a is " + a);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

}

}

ขอมูล ตัวแปร และ การประมวลผล

26

a = b / c * d; System.out.println("Value of a is " + a);

ผลลัพธที่ไดจากการ run คือ b = 8 Value Value Value

c = 2 d of a is of a is of a is

= 6 e = 5 4 10 24

การประมวลผล เมื่อมีตัวแปรหลายตัวในการประมวลผลของประโยค ลําดับขั้น (precedence) ของการประมวลผลมี ความสําคัญทันที ทั้งนี้ก็เนื่องมาจากรูปแบบของการประมวลผลตามชั้นของ operator ตาง ๆ มีลําดับการ ประมวลผลที่ไมเทากัน (กอน หรือ หลัง) ซึ่งเปนไปตามลําดับขั้นของการประมวลผลตามกฎของการ ประมวลผลทางดานคณิตศาสตร ดังตารางที่ 2.4 ตาราง 2.4 Operator Precedence Operator ตามกลุม (), [], ., postfix ++, postfix -unary +, unary –, prefix ++, prefix -(datatype), new *, /, % +, <<, >>, >>> <, <=, >, >=, instance of ==, != & ^ | && || ?: =, +=, -=, *=, /=, %=, <<=, >>=, >>>=, &=, |=, ^=

การประมวลผล ซายไปขวา ขวาไปซาย ซายไปขวา ซายไปขวา ซายไปขวา ซายไปขวา ซายไปขวา ซายไปขวา ซายไปขวา ซายไปขวา ซายไปขวา ซายไปขวา ซายไปขวา ซายไปขวา ขวาไปซาย

การประมวลผลขอมูลที่เปน integer การประมวลผลขอมูลที่เปน integer ทั้งหมดไมมีความสลับซับซอนอะไรเลย เปนการประมวลผล เหมือนกับที่เราเคยเรียนมา ในวิชาคณิตศาสตรซึ่งลําดับขั้นของการประมวลผลก็ขึ้นอยูกับชนิดของ operator ที่ใชในการประมวลผลนั้น ๆ เชน การคูณและการหาร ทํากอน การบวกและการลบ statement 50 * 2 – 45 / 5 จะไดผลลัพธคอ ื 91 ซึ่งไดมาจากการนําเอา 2 ไปคูณ 50 กอนหลังจากนั้นก็เอา 5 ไปหาร 45 เมื่อไดแลว ก็นําเอาผลลัพธที่ไดไปลบออกจากผลลัพธของการคูณ 50 กับ 2 ซึ่งมีคาเทากับ 100 – 9 แตถา เราตองการทีจ ่ ะใหการประมวลผลอยูในรูปแบบอื่น ที่เราตองการเราก็ใชวงเล็บเปนตัวกําหนด เชน ถาเราตองการที่จะใหการลบเกิดกอน ในประโยคที่เห็นกอนหนานี้เราก็เขียนใหมเปน 50 * (2 – 45) / 5 ซึ่งมีคาเทาเทียมกับประโยค 50 * -43 / 5

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

27

และมีคาเทากับ -430 เนื่องจากวาการประมวลผลขอมูลที่เปน integer โดยเฉพาะการหารนั้น เราจะไมมีเศษเหลือใหทาํ การหาร ตอไปเหมือนทีเ่ ราเคยหารกันมา เชน ถาเราเอา 4 ไปหาร 9 เราก็จะได 2.25 แตถาเปนการหารดวย integer ใน Java แลวผลลัพธที่เราไดจากการหารนี้จะเปน 2 เทานั้น เราจะไมไดเศษ เราจะไดแตสวน ลองดูตัวอยางตอไปนี้ 5/2=2 125 / 4 = 31 3/9=0 15 / 15 = 1 แตเราก็หาเศษไดดวยการใช operator % ดังที่ไดแสดงในโปรแกรมตัวอยางกอนหนานี้ หรือดังตัวอยาง การหาเศษตอไปนี้ 5%2=1 125 % 4 = 1 3%9=3 15 % 15 = 0 โดยทั่วไปเทาที่พบเห็นและประสพมา ผูอานที่ใหมตอการเขียนโปรแกรม มักจะสับสนในเรือ ่ งของการหา เศษ หรือการหาสวนของขอมูลที่เปน integer อยางไรก็ตามเรื่องเหลานี้มักจะหายไปถาไดทดลองทํา อยางสม่ําเสมอ สําหรับ Java นั้นการหาเศษสามารถที่จะทําไดกับขอมูลที่เปน double หรือ float ดวย แต ในที่นี้จะทิ้งไวใหผูอานไดทดลองทําการตรวจสอบดูเอง (เนื่องจากวาผูเขียนเองยังมองไมเห็นประโยชน ของการหาเศษจากขอมูลที่เปน double หรือ float เลย) ในการเขียนโปรแกรมนั้นเราเก็บขอมูลไวในตัวแปร ดังนั้นการประมวลผลก็ตอ  งทํากับตัวแปรเหลานั้น เชน เราสามารถทีจ ่ ะคํานวณหาคาของภาษีมูลคาเพิ่ม (vat) จากตัวแปร price และ rate ถาตัวแปรทั้งสอง ไดรับการกําหนดคาเรียบรอยแลว เชน double price = 120.0, rate = 7.5; double vat = price * rate; ลองมาดูโปรแกรมตัวอยางการประมวลผลดวยขอมูลที่เปน integer /* * Integer.java - Integers calculation */ class Integer { public static void main(String[] args) { //declares and initialize three variables int studentNumber = 40; int teacherNumber = 30; int totalNumber = 0; totalNumber = studentNumber + teacherNumber;

}

}

//display result System.out.print(studentNumber + " students + " + teacherNumber); System.out.println(" teachers = " + totalNumber + " people");

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

28

โปรแกรม Integer.java เปนการแสดงถึงการคํานวณหาคาของผลรวมของจํานวนนักศึกษา (studentNumber)และครู (teacherNumber) จากประโยค totalNumber = studentNumber + teacherNumber; ซึ่งขั้นตอนของการประมวลผล อาจพูดไดคราว ๆ คือ Java นําเอาคาที่เก็บไวในตัวแปร studentNumber และคาที่เก็บไวในตัวแปร teacherNumber มารวมกันและนําเอาผลลัพธที่ไดไปเก็บไวในตัวแปร totalNumber ผานทางเครื่องหมาย = (assignment operator) ลองดูภาพที่ 2.2

teacherNumber

studentNumber

40

totalNumber

+

30

70

ภาพที่ 2.2 การบวก integer สองตัว

ในการแสดงผลลัพธที่ไดจากการประมวลผลไปยังหนาจอนั้น เราสงผานทาง System.out.print() และ System.out.println() ประโยค System.out.print(studentNumber + " students + " + teacherNumber); จะใหผลลัพธคอ ื คาที่เก็บไวในตัวแปร studentNumber ตามดวย string ทีม ่ ีคาเปน "student +" ตาม ดวยคาที่เก็บไวในตัวแปร teacherNumber ในบรรทัดเดียวกัน หลังจากนั้นประโยค System.out.println(" teachers = " + totalNumber + " people"); ก็จะใหผลลัพธ คือ string ที่มค ี าเปน " teachers = " ตามดวยคาที่เก็บไวในตัวแปร totalNumber ตาม ดวย string ที่มค ี าเปน " people" ซึ่งเมื่อรวมแลวทั้งหมดก็จะไดผลลัพธทแ ี่ สดงไปยังหนาจอดังนี้ 40 students + 30 teachers = 70 people คําวา "ตามดวย" จากคําอธิบายดานบนนี้เกิดจากการประมวลผลของ Java กับเครื่องหมาย + ในการใช ประโยคของการแสดงผล (System.out) ขอมูลใด ๆ ที่อยูในเครื่องหมาย " " จะถูกสงไปยังหนาจอ แตถา เปนตัวแปรหรือประโยคทีต ่ องมีการประมวลผลอีก Java จะทําการประมวลผลกอนเพื่อใหไดคาสุดทายที่ สามารถจะสงออกไปหนาจอได เชน System.out.println("30 + 45 = " + (30 + 45)); สิ่งทีถ ่ ูกสงออกไปกอนคือ "30 + 45 = " ตามดวยคาของการประมวลผลของประโยค (30 + 45) ซึ่งก็คือ 75 ดังนั้นผลลัพธที่สงไปยังหนาจอคือ 30 + 45 = 75 วงเล็บในประโยคของการบวก 30 กับ 45 ก็มีสวนสําคัญเพราะถาไมมี Java ก็จะแสดงผลเปน

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

29

30 + 45 = 3045 การใสวงเล็บเปนการบอก Java ใหทําการคํานวณหาคาของประโยคนั้น ๆ ทั้งนี้เฉพาะในประโยคทีใ่ ช System.out เทานั้น สวนการประมวลผลที่อน ื่ ๆ ก็ทําตามเดิม เหตุที่เปนเชนนี้ก็เพราะวา System.out จะ นําคานั้น ๆ ที่เปนอยูไปแสดงถาไมมีการคํานวณใด ๆ สมมติวาเราตองทําการบวกคาใดคาหนึ่งใหกับตัวแปร เราก็สามารถที่จะสรางประโยคไดเหมือนกับที่เรา เคยทํามากอนหนานี้ เชน total = total + value; ถาเราลองเขียนภาพแทนประโยคดังกลาว เราก็อาจเขียนไดดังนี้

value

total

total

+

value

ภาพที่ 2.3 การเพิ่มคาใหกับตัวแปรตัวเดิม

ประโยคที่เห็นดานบนนี้สามารถที่จะเขียนอีกแบบได ดังนี้คือ total += value; เราใชเครื่องหมาย += ในการสรางประโยคของเรา แตไดผลลัพธเชนเดียวกันกับประโยคกอนหนานี้ และ ลดเวลาในการเขียนลง (ถึงแมวาจะไมมากก็ตาม) เชนเดียวกับการประมวลผลดวย operator ตัวอื่น ๆ เรา ก็สามารถจะใชวิธีเดียวกันนี้ได ดังที่ไดสรุปไวใน ตาราง 2.5 ตาราง 2.5 การใช operator ประโยคตัวอยาง sum = sum + count; sum = sum - count; sum = sum * count; sum = sum / count; sum = sum % count;

ตาง ๆ รวมกับการกําหนดคา ประโยคที่ไดผลลัพธเหมือนกัน sum += count; sum -= count; sum *= count; sum /= count; sum %= count;

การกําหนดคาแบบนี้ไมจําเปนที่จะตองทํากับตัวแปรเทานั้น เราสามารถที่จะทํากับคาคงทีอ ่ ื่น ๆ ได เชน total += 4; sum += 1; ยังมี operator ที่เราสามารถใชไดโดยไมตองเสียเวลาในการเขียนมากมายนัก เชน การเพิ่ม หรือ ลดทีละ หนึ่งคา ดังประโยคตัวอยาง count = count + 1; value -= 1;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

30

ทั้งสองประโยคที่เห็นดานบนทําการเพิ่มคาและลดคาทีละหนึง่ คา ตามลําดับ เราสามารถที่จะเขียนใหม ดวยการใช operator ++ และ operator -- ไดดังนี้ คือ count++; value--; จะเห็นวาถาเราตองการเพิ่มคาเพียงแคหนึ่งคาเราก็ใชเครื่องหมาย ++ ตามหลังตัวแปรนั้น เชนเดียวกันถา เราตองการลดคาลงหนึ่งคา เราก็ใชเครื่องหมาย –- ตามหลังตัวแปรนั้น เราเรียกการเขียนแบบนี้วา การ เขียนแบบ postfix (postfix notation) ซึ่งเปนการใช operator ตามหลังตัวแปร และ Java ยอมใหมีการ เพิ่มหรือลดคาไดเพียงแคหนึง่ คาเทานั้น ถาเราตองการเพิ่มหรือลดคามากกวาหนึ่งคา เราตองใชวิธส ี องวิธี ที่ไดแสดงการใชกอนหนานี้ เชน ถาตองการเพิ่มทีละสอง เราก็เขียนเปน total += 2; และถาเราตองการลดทีละสาม เราก็เขียนเปน total -= 3; Java ยังมี Operator อีกตัวหนึง่ ที่เราสามารถเลือกใช ในการประมวลผลถาเราคํานึงถึงขั้นตอนของการ ประมวลผล วาควรจะทําอะไรกอน อะไรหลัง ดังประโยคตัวอยางตอไปนี้ int count = 8, value = 5; count = count + value++; ถามองดูเผิน ๆ เราก็อาจบอกวาประโยคนี้เปนการบวกคาของตัวแปร value เขากับตัวแปร count พรอมกับ การเพิ่มคาใหกับตัวแปร value อีกหนึ่งคา แตเรารูหรือไมวาอะไรไดรับการประมวลผลกอน count + value กอน หรือ value++ กอน และผลลัพธที่ไดจากการบวกคืออะไร จากประโยคดานบน Java จะนําเอาคาของ value มาบวกเขากับคาของ count กอน หลังจากนั้นจึงเพิ่มคา ใหกับตัวแปร value อีหนึ่งคา ดังนั้นถาเรา execute ประโยค count = count + value++ เราก็จะได ผลลัพธเปน 13 และคาของ value หลังจากการบวกจะเปน 6 แตถา เราเปลี่ยนประโยคใหเปนดังนี้ count = count + ++value; เราจะไดผลลัพธจากการบวกเปน 14 (ทําไม) เนื่องจากวาเราใชเครื่องหมาย ++ นําหนาตัวแปร ดังนั้น Java จึงทําการเพิม ่ คาใหกับตัวแปร value กอน หลังจากนั้นจึงนําคาที่ไดนี้ไปบวกเขากับคาของตัวแปร count ผลลัพธที่ไดจึงเปน 14 ดังที่เห็น เราเรียก การเขียนแบบนีว้ าการเขียนแบบ prefix (prefix notation) ขึ้นอยูกับตําแหนงที่ใช prefix หรือ postfix ในประโยค บางครั้งการประมวลผลจาก Java อาจไดผลลัพธ ที่เหมือนกัน เราจะกลับมาพูดถึงกรณีดังกลาวในเรื่องของการทํางานแบบวน หรือ loop (repetition) ลองมาดูตวั อยางการใช prefix และ postfix กันอีกสักหนอย int count = 10, value = 5; count--; value++; value = ++count + ++value; ถาเรา execute ประโยค value = ++count + --value; เราก็จะไดผลลัพธ คือ value มีคาเปน 17 เพราะ กอนหนานั้น count มีคาเปน 9 และ value มีคาเปน 6 (จาก count—และ value++) แตไดรับการเพิ่มให อีกหนึ่งคากอนการบวกในประโยคสุดทาย

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

31

ถาหากวาเราตองการให code ที่เขียนนั้นอานไดงายขึ้นเราก็อาจใชวงเล็บเปนตัวชวยก็ได เชน value = (++count) + (++value); หรืออาจเขียนใหดูแลวเวียนหัวแบบนี้ value = (count += 1) + (value += 1); หรือแบบนี้ value = (count = count + 1) + (value = value + 1); สวนประโยคตอไปนี้จะใหผลลัพธตางจากตัวอยางดานบน (ทําไม?) value =

(count++) + (value++);

ถาเราลองวิเคราะหประโยคดานบนนี้ ดวยคาของ count = 10 และคาของ value = 5 และตามขอกําหนด การใชงานของ postfix ++ เราก็ตองสรุปวา Java จะนําเอาคาของ count ซึ่งมีคาเทากับ 10 บวกเขากับ คาของ value ซึ่งมีคาเทากับ 5 เมื่อไดแลวก็นําผลลัพธที่ไดไปเก็บไวในตัวแปร value ดังนั้น value จึงมี คาเทากับ 15 หลังจากนั้นก็จะเพิ่มคาใหกับ count และ value อีกหนึ่งคา ซึ่งทําให count มีคาเทากับ 11 และ value มีคาเทากับ 16 แตเมื่อทดลอง run ดูแลวผลลัพธที่ไดกลับเปน value = 15 และ count = 11 ทําไม? เพื่อใหเกิดความ กระจางเราก็ทดลองเขียนประโยคตรวจสอบใหม คือ value = 5; value = value++; และเมื่อ run ดูเราก็ไดผลลัพธเปน value = 5 ทําใหเราคอนขางจะมั่นใจวา Java ไมยอมให postfix operator ++ เพิ่มคาใหกับตัวแปรเดิมที่ไดรบ ั การกําหนดคาในประโยคเดียวกัน แตเพื่อใหแนใจขึ้นอีกเรา ก็ทดลอง run ดวยประโยค int sum = value++; เราไดผลลัพธเปน sum มีคาเทากับ 5 และ value มีคาเทากับ 6 ดังนั้นเราจึงมั่นใจวา postfix operator ++ ไมยอมใหมีการเพิ่มคาใหกับตัวแปรตัวเดียวกันกับที่ใชในการกําหนดคาในประโยคเดียวกัน (ดังที่ได กลาวไว) การเขียนโปรแกรมทีด ่ ีนั้นไมควรเขียนใหอานยาก เชนตัวอยางของการใช ++ ที่ไดกลาวถึงกอนหนานี้ ถา การเขียนนั้นไดผลลัพธดังที่เราตองการ ถึงแมวาจะเขียนดวยประโยคหลาย ๆ ประโยค ก็ยงั ดีกวาที่เขียน ดวยจํานวนประโยคที่สั้น แตอา นไดยากกวา ตัวอยางตอไปนี้เปนการใช operator ++ และ operator – ในรูปแบบตาง ๆ /* Increments.java - Shows increment operators */ class Increments { public static void main(String[] args) { int value = 25, number = 25; System.out.println("value is " + value); System.out.println("number is " + number); --value; number++; System.out.println("value is " + value); System.out.println("number is " + number); value = value + --number; System.out.println("value is " + value);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

}

}

ขอมูล ตัวแปร และ การประมวลผล

32

System.out.println("number is " + number); number = number - value++; System.out.println("value is " + value); System.out.println("number is " + number); number--; value++; System.out.println("value is " + value); System.out.println("number is " + number); value = --value; number = number++; System.out.println("value is " + value); System.out.println("number is " + number);

ผลลัพธที่ไดจากการ run value is 25 number is 25 value is 24 number is 26 value is 49 number is 25 value is 50 number is -24 value is 51 number is -25 value is 50 number is -25 ผูอานควรทดสอบการใช operator increment ทั้งสอง (++ และ --) ในประโยคสมมติตาง ๆ เพื่อใหเกิด ความเขาใจในการใช operator ทั้งสองไดดย ี ิ่งขึ้น การประมวลผลดวย integer ขนาดเล็ก (short และ byte) ในการประมวลผลดวยขอมูลทีเ่ ปน byte หรือ short นั้น Java จะทําการประมวลผลเชนเดียวกันกับการ ประมวลผลดวยขอมูลที่เปน int และผลลัพธของการประมวลผลขอมูลที่เปน short หรือ byte นั้นจะถูก เก็บอยูในรูปแบบของขอมูลที่เปน int ดังตัวอยางตอไปนี้ /* ByteShort.java - Shows byte and short integer calculation */ class ByteShort { public static void main(String[] args) { short numScooters = 10; short numChoppers = 5; short total = 0; total = numScooters + numChoppers;

}

}

System.out.println("Number of scooters is " + numScooters); System.out.println("Number of choppers is " + numChoppers); System.out.println("Total number of bikes is " + total);

เมื่อได compile แลว Java จะฟองวามี error เกิดขึ้น ByteShort.java:10: possible loss of precision

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

33

found : int required: short total = numScooters + numChoppers; ^ 1 error เนื่องจากวาผลลัพธของการบวกจะตองเก็บเปน integer ที่มีขนาดเทากับ 64 bit แตตัวแปร total สามารถ เก็บขอมูลไดสงู สุดเทากับ 16 bit ดังนั้น compiler จึงฟองทันที วิธีการแกไขก็อาจจะตองเปลี่ยนตัวแปร ทั้งสามใหเปน int หรือไมก็ใชวิธีการเปลี่ยนชนิดของขอมูลทีเ่ รียกวา casting การเปลี่ยนแปลงชนิดของขอมูลดวยการ cast ในการ cast นั้นเราจําเปนทีจ ่ ะตองคํานึงถึงการจัดเก็บขอมูลวาเราจะตองใชขอมูลชนิดไหน ในการจัดเก็บ การประกาศตัวแปรก็ตองทําดวยความระมัดระวัง เนื่องจากวาการ cast นั้นถาเรา cast ขอมูลที่มีขนาด ใหญไปสูขอมูลที่มีขนาดเล็ก เราจะสูญเสียคาความเปนจริงของขอมูลนั้น เรามาทําการแกไขโปรแกรม ByteShort.java เพื่อให Java ยอมใหการ compile เปนไปไดดวยดีกันดีกวา วิธีการก็ไมยากเพียงแตเปลี่ยนประโยค total = numScooters + numChoppers; ใหเปน total = (short)(numScooters + numChoppers); เทานี้ Java ก็ยอมใหเรา compile และเมื่อเราทดลอง run ดูก็ไดผลลัพธดงั ที่คาดไว คือ Number of scooters is 10 Number of choppers is 5 Total number of bikes is 15 ทีนี้เราลองมาดูกันวาถาเราเปลีย ่ นคาของ numScooters ใหเปน 32767 ดังที่เห็นดานลาง ผลลัพธที่ไดใน การ compile และ run โปรแกรมของเราจะเปนอยางไร short numScooters = 32767; short numChoppers = 5;

//คาสูงสุดที่เปนไปได

ผลลัพธที่ได คือ Number of scooters is 32767 Number of choppers is 5 Total number of bikes is -32764 จะเห็นวาคาของ total เปน -32764 ซึ่งเปนคาที่ไมถูกตอง ซึ่งถาบวกกันแลวคาที่ไดตองเปน 32772 ทําไม? เนื่องจากวาตัวแปรทั้งสามตัวมีชนิดเปน short และสามารถเก็บขอมูลไดสงู สุดเพียงแค 32767 ดังนั้นการ นําเอาผลรวมทีม ่ ีคาเกินกวาคาสูงสุดที่เปนไปไดมาเก็บไวในตัวแปร total จึงไมสามารถทําไดแต Java ก็ จะนําเอาคาอื่นที่ไดจากการประมวลผล (ที่ถูกตองตามหลักการแตมีคาความคลาดเคลื่อนของการ ประมวลผล – จํานวน bit ที่ใชในการคํานวณหายไปครึ่งหนึ่ง จาก 64 bit เหลือเพียง 32 bit) มาใสไวให ผูเขียนโปรแกรมจะตองทําความเขาใจเกี่ยวกับชนิดของของมูล และการประมวลผลตามชนิดนั้น ๆ ของ ขอมูล ถาหากวาหลีกเลี่ยงได ผูเขียนโปรแกรมก็ควรหลีกเลี่ยงการใช cast นอกเสียจากวาจําเปนตองใช จริง ๆ เทานั้น เรามาดูการ cast อื่น ๆ จากโปรแกรม Casting.java /* Casting.java - Changing type of data */ class Casting { public static void main(String[] args) { byte byteVar = 127;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

34

short shortVar = 32767; long longVar = 100000; int intVar = 300000; System.out.println("byteVar is " + byteVar); System.out.println("shortVar is " + shortVar); System.out.println("longVar is " + longVar); System.out.println("intVar is " + intVar); byteVar = (byte)shortVar; shortVar = (short)longVar; longVar = (int)intVar * (int)longVar; intVar = (short)intVar * (short)intVar;

}

}

System.out.println("byteVar is " + byteVar); System.out.println("shortVar is " + shortVar); System.out.println("longVar is " + longVar); System.out.println("intVar is " + intVar);

ผลลัพธที่ไดจากการ run คือ byteVar is 127 shortVar is 32767 longVar is 100000 intVar is 300000 byteVar is -1 shortVar is -31072 longVar is -64771072 intVar is 766182400 ในการประมวลผลดวยการใชขอ  มูลที่มช ี นิดเปน long นั้น (บังคับใหเปน long ดวยการใส L ดานหลังคาที่ กําหนดใหกับตัวแปรนั้น ๆ) ขอมูลชนิดอื่นจะถูกเปลี่ยนใหเปน long กอนการประมวลผล เชน long value = 125; long price = 200L; int total = 0; total = value * price; กอนการประมวลผลคาของตัวแปร value จะถูกเปลี่ยนใหเปน long แลวจึงนํามาคูณกับตัวแปร price เพราะฉะนั้นในการประมวลผลขอมูลที่เปน integer นั้นขอควรคํานึงถึงก็คือ o o

การประมวลผลกับตัวแปรที่ประกาศเปน long ที่มีการกําหนดคาดวยตัว L จะเปนการประมวลผล ดวยการใชจํานวน bit เทากับ 64 bit การประมวลผลกับตัวแปรที่ประกาศเปน int จะเปนการประมวลผลดวยการใชจํานวน bit เทากับ 32 bit

ปญหาของการประมวลผลดวยขอมูลที่มีชนิดเปน integer o

o

ถาเราหารตัวแปรที่มช ี นิดเปน int ดวย 0 เราไมสามารถหาคําตอบได เพราะฉะนั้น Java จะทํา การฟองดวย error แตเราก็สามารถที่จะตรวจสอบและแกไขไดดวยการใช exception ซึ่งเปนวิธี ดักจับ error ที่ Java เอื้ออํานวยใหผูเขียนโปรแกรมไดทําการเอง เราจะพูดถึง exception ใน โอกาสตอไป การประมวลผลดวยคาที่เกินขีดจํากัดของตัวแปรจะทําใหไดผลลัพธที่คลาดเคลื่อน

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

o

ขอมูล ตัวแปร และ การประมวลผล

35

การประมวลผลดวย % ที่มค ี าของ 0 อยูทางขวาก็ทําใหเกิด error เหมือนกับการหารดวย 0

การประมวลผลดวยตัวแปรที่มีจุดทศนิยม (Floating Point Calculations) การประมวลผลของขอมูลที่เปนเลขทศนิยมนัน ้ ก็คลายกันกับการประมวลผลดวยขอมูลที่เปน integer การ ใช operator ตาง ๆ ก็เหมือนกัน คือ + - * / ลองมาดูตวั อยางกัน /* FloatingPoint.java - Calculating income */ class FloatingPoint { public static void main(String[] args) { double weeklyPay = 1075 * 5; //1075 per day double extras = 1580; final double TAX_RATE = 8.5; //tax rate in percent //calculate tax and income double tax = (weeklyPay + extras) * TAX_RATE / 100; double totalIncome = (weeklyPay + extras) - tax;

}

}

System.out.println("Tax = " + tax); System.out.println("Total income = " + totalIncome);

โปรแกรม FloatingPoint.java เปนการคํานวณหาภาษี และรายไดตอหนึ่งอาทิตย โดยเราสมมติใหรายได ตอวันเทากับ 1075 บาท และรายไดพิเศษเทากับ 1580 บาท อัดตราภาษีเทากับ 8.5% เมื่อเรา execute โปรแกรมเราก็จะไดผลลัพธดงั นี้ Tax = 591.175 Total income = 6363.825 ในการคํานวณหาภาษีนั้นเราจําเปนที่จะตองใชวงเล็บในประโยค double tax = (weeklyPay + extras) * TAX_RATE / 100; เนื่องจากวาเราตองการใหการบวกทํากอนการคูณและการหาร ถาไมเชนนัน ้ แลวเราจะไมไดคารายได โดยรวมที่เปนจริง ถาเราสังเกตใหดีผลลัพธที่ไดจะมีเลขหลังจุดทศนิยมอยูสามตัว เราทําใหเปนสองตัว ดังที่ใชกันอยูท  วั่ ไปไดมั้ย? คําตอบก็คือ ได ดวยการเพิ่ม code เขาไปในโปรแกรมดังนี้ /* FloatingPoint2.java - Calculating income with formatted output */ import java.text.*; //for NumberFormat class FloatingPoint2 { public static void main(String[] args) { double weeklyPay = 1075 * 5; //1075 per day double extras = 1580; final double TAX_RATE = 8.5; //tax rate in percent //set format output NumberFormat form = NumberFormat.getNumberInstance(); form.setMaximumFractionDigits(2); //calculate tax and income double tax = (weeklyPay + extras) * TAX_RATE / 100; double totalIncome = (weeklyPay + extras) - tax; System.out.println("Tax = " + form.format(tax)); System.out.println("Total income = " + form.format(totalIncome));

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

}

ขอมูล ตัวแปร และ การประมวลผล

36

}

เราเพิ่มประโยค NumberFormat form = NumberFormat.getNumberInstance(); form.setMaximumFractionDigits(2); และเปลี่ยนการแสดงผลลัพธดว ยการใช form.format(tax) และ form.format(totalIncome) เพื่อให ผลลัพธที่ออกมาเปน Tax = 591.18 Total income = 6,363.82 จะเห็นวา 591.175 จะถูกปดใหเปน 591.18 และ 6363.825 ถูกปดใหเปน 6363.82 โดยที่คาของ totalIncome มี , (comma) เปนตัวบอกถึงจํานวนของหลักรอยดวย ในการใช method ทั้ง getNumbereInstance() และ setMaximumFractionDigits() นั้นเราจําเปนที่ จะตอง import class NumberFormat เขาสูโ ปรแกรมของเรา ถาไมแลวเราจะไมสามารถใช method เหลานี้ได ยังมี method อื่นใน class DecimalFormat ที่เราสามารถเรียกใชในการ format ผลลัพธที่เปนจุดทศนิยม ได เชนถาเราไมตองการ , (comma) เปนตัวแบงหลักเราจะทําอยางไร? ลองดูตัวอยางนีด ้ ู /* FloatingPoint3.java - Calculating income with formatted output */ import java.text.*; //for DecimalFormat class FloatingPoint3 { public static void main(String[] args) { double weeklyPay = 1075 * 5; //1075 per day double extras = 1580; final double TAX_RATE = 8.5; //tax rate in percent //set format output DecimalFormat form = new DecimalFormat("#.00"); //calculate tax and income double tax = (weeklyPay + extras) * TAX_RATE / 100; double totalIncome = (weeklyPay + extras) - tax;

}

}

System.out.println("Tax = " + form.format(tax)); System.out.println("Total income = " + form.format(totalIncome));

ผลลัพธที่ไดคอ ื Tax = 591.18 Total income = 6363.82 เราเพียงแตเรียกใช class DecimalFormat แทน NumberFormat และเปลี่ยนการกําหนด format ใหเปน DecimalFormat form = new DecimalFormat("#.00); เราก็จะไดผลลัพธที่มีเลขหลังจุดทศนิยมอยูส  องตัว และไมมี , (comma) เปนตัวแบงหลัก ยังมีวิธีการ กําหนดรูปแบบของการแสดงผลลัพธอีกมากมายแตเราก็คงจะพูดเพียงเทานี้กอน

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

37

การประมวลผลขอมูลตางชนิดกัน (Mixed Type Calculations) ในการประมวลผลขอมูลที่มีความหลากหลายของชนิดในประโยคใด ๆ นั้น โดยทั่วไป Java จะทําการ เปลี่ยนชนิดของขอมูลที่มีขนาดเล็กกวาใหเปนขนาดทีใ่ หญที่สด ุ ในกลุมของขอมูลนั้น ๆ แตผูเขียน โปรแกรมจะตองใชความระมัดระวังในเรื่องของการจัดเก็บขอมูลที่มีขนาดใหญไปไวในตัวแปรที่มีขนาด เล็ก เชนเดียวกับที่ไดทํามากอนหนานี้ในเรื่องของการประมวลผลขอมูลที่เปน integer ลองมาดูตัวอยาง กัน /* FloatingPoint4.java - Mixed-type calculations */ import java.text.*; //for NumberFormat class FloatingPoint4 { public static void main(String[] args) { double hourlyPay = 85.50; //85.50 per hour int hoursPerDay = 8; //8 hours per day int numberOfDays = 5; //total days worked int extraHoursWorked = 15; //overtime hours final double TAX_RATE = 8.5;//tax rate in percent //set format output NumberFormat form = NumberFormat.getNumberInstance(); form.setMaximumFractionDigits(2); //calculate weekly pay double weeklyPay = hourlyPay * hoursPerDay * numberOfDays; //calculate extra pay: one and a half time of //regular hourly pay double extras = extraHoursWorked * (hourlyPay + (hourlyPay / 2.0)); //calculate tax double tax = (weeklyPay + extras) * TAX_RATE / 100; //calculate total income double totalIncome = (weeklyPay + extras) - tax;

}

}

System.out.println("Income before tax = " + form.format((weeklyPay + extras))); System.out.println("Tax = " + form.format(tax)); System.out.println("Income after tax = " + form.format(totalIncome));

โปรแกรม FloatingPoint4.java ใชตัวแปรที่มช ี นิดเปนทั้ง double และ integer ปนกันในการคํานวณหา รายไดตอหนึ่งอาทิตย โดยกําหนดใหตัวแปร hoursPerDay numberOfDays และ extraHoursWorked เปน integer สวนตัวแปร hourlyPay weeklyPay extras tax และ totalIncome เรากําหนดใหเปน double การประมวลผลก็ไมยุงยากอะไร Java จะเปลีย ่ นตัวแปรที่เปน int ใหเปน double กอนการประมวลผล เพราะฉะนั้นการจัดเก็บผลลัพธก็ไมมีคาความคลาดเคลื่อนใด ๆ เกิดขึ้น ดังผลลัพธที่แสดงนี้ Income before tax = 5,343.75 Tax = 454.22 Income after tax = 4,889.53 ขอควรจําในการประมวลผลขอมูลตางชนิดกัน (ในประโยคเดียวกัน) o

ถามีตวั แปรใดเปน double ตัวแปรที่นํามาประมวลผลดวยจะถูกเปลี่ยนใหเปน double กอนการ ประมวลผล

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

o o

ขอมูล ตัวแปร และ การประมวลผล

38

ถามีตวั แปรใดเปน float ตัวแปรที่นํามาประมวลผลดวยจะถูกเปลี่ยนใหเปน float กอนการ ประมวลผล ถามีตวั แปรใดเปน long ตัวแปรที่นํามาประมวลผลดวยจะถูกเปลี่ยนใหเปน long กอนการ ประมวลผล

สิ่งทีส ่ ําคัญก็คอ ื ขอมูลที่เล็กกวาในประโยคจะถูกเปลี่ยนใหเปนชนิดที่ใหญที่สด ุ ในประโยคนั้น ๆ ซึ่ง บางครั้งก็ไมใชการประมวลผลที่เราตองการ เชน ตัวอยางของโปรแกรมตอไปนี้ /* MixedTypes.java - Mixed-type calculations */ import java.text.*; class MixedTypes { public static void main(String[] args) { double result = 0.0; int one = 1, two = 2;

}

}

result = 1.5 + one / two; //formatting output DecimalFormat f = new DecimalFormat("#.00"); System.out.println("Result is " + f.format(result));

ผลลัพธที่เราคาดหวังวาจะได คือ 2.0 แต Java กลับให 1.5 ซึ่งเปนผลลัพธที่เราไมตองการ ถาสังเกตให ดีจะเห็นวาประโยค result = 1.5 + one / two; นั้น การหารจะเกิดกอน และเนื่องจากวาทั้ง one และ two เปน int ดังนั้นผลลัพธของการหารจึงมีคาเปน int และมีคาเปน 0 หลังจากนัน ้ Java ก็จะเปลี่ยน 0 ที่ไดใหเปน double แลวจึงทําการบวกเขากับ 1.5 เพื่อใหผลลัพธเปนที่เราตองการ ดังนั้นเราจึงตองทําการ cast ใหตัวแปร one เปน double เสียกอน ดังนี้ /* MixedTypes.java - Mixed-type calculations */ import java.text.*; class MixedTypes { public static void main(String[] args) { double result = 0.0; int one = 1, two = 2;

}

}

result = 1.5 + (double)one / two; //formatting output DecimalFormat f = new DecimalFormat("#.00); System.out.println("Result is " + f.format(result));

เราก็จะไดผลลัพธเปน 2.0 ดังที่เราตองการ อยางไรก็ตามการ cast นั้นตองใชความระมัดระวังเปนพิเศษ หากเราทําการ cast ขอมูลทีใ่ หญกวาไปเก็บ ไวในตัวแปรที่เล็กกวาก็จะทําใหเกิดความคลาดเคลื่อนของขอมูลได ดังที่ไดพูดไวกอนหนานี้ เรามาลองดูตัวอยางอีกตัวอยางหนึ่ง /* FloatingPoint5.java - Mixed-type calculations */ import java.text.*;

//for NumberFormat

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

39

class FloatingPoint5 { public static void main(String[] args) { double hourlyPay = 85.50D; //85.50 per hour int hoursPerDay = 8; //8 hours per day float numberOfDays = 5F; //total days worked int extraHoursWorked = 15; //overtime hours final double TAX_RATE = 8.5D;//tax rate in percent //set format output NumberFormat form = NumberFormat.getNumberInstance(); form.setMaximumFractionDigits(2); //calculate weekly pay double weeklyPay = hourlyPay * hoursPerDay * numberOfDays; //calculate extra pay: one and a half time of regular hourly pay double extras = extraHoursWorked * (hourlyPay + (hourlyPay / 2.0)); //calculate tax double tax = (weeklyPay + extras) * TAX_RATE / 100; //calculate total income double totalIncome = (weeklyPay + extras) - tax;

}

}

System.out.println("Income before tax = " + form.format((weeklyPay + extras))); System.out.println("Tax = " + form.format(tax)); System.out.println("Income after tax = " + form.format(totalIncome));

เราไดเปลี่ยนประโยค int numberOfDays = 5; ใหเปน float numberOfDays = 5F; และผลลัพธที่ไดก็ ยังคงถูกตองเหมือนเดิมทั้งนี้เพราะ Java จะเปลี่ยน float ใหเปน double เชนเดียวกันกับที่เปลี่ยน int ให เปน double จากตัวอยางกอนหนานี้ การใช Mathematical Functions ตาง ๆ ที่ Java มีให หลาย ๆ ครั้งทีก ่ ารเขียนโปรแกรมตองการใช function ที่เกี่ยวของกับการหาคาทางคณิตศาสตร เชน การ หาคาของ sine cosine tangent หรือ คาอื่น ๆ ที่เกี่ยวของกับการคํานวณทางคณิตศาสตร Java ก็ไดทํา การออกแบบและจัดสรร function เหลานี้ไวใหผูใชไดเรียกใชอยางเต็มที่ เราจะมาทดลองเรียกใช function ตาง ๆ เหลานี้ดู ตัวอยางตอไปนี้จะเปนการคํานวณหาคาของสมการ ที่เรียกวา Quadratic Equation Æ ax2 + bx + c = 0 ซึ่งหาไดจากการใชสูตร

x1 =

− b + b 2 − 4ac 2a

x2 =

− b − b 2 − 4ac 2a

ซึ่ง mathematical function ที่เราตองใชก็คอ ื การหา square root และ Java ไดจัดเตรียม method ตัว นี้ไวใหเราแลวก็คือ Math.sqrt() เรามาลองดูโปรแกรมที่หาคาของสมการตัวนี้กันดู /* Quadratic.java - Calculating roots of function */

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

40

class Quadratic { public static void main(String[] args) { double a, b, c; //4x2 + 20x + 16 = 0 a = 4; b = 20; c = 16; //calculate determimant double det = Math.sqrt(b * b - 4 * a * c); //calculate roots double x1 = (-b + det) / (2 * a); double x2 = (-b - det) / (2 * a);

}

}

System.out.println("Root 1 = " + x1); System.out.println("Root 2 = " + x2);

ผลลัพธที่ไดคอ ื Root 1 = -1.0 Root 2 = -4.0 ในการเขียนโปรแกรม Quadratic.java ในครัง้ นี้นั้นเราจะยังไมสนใจในเรื่องที่คาของ determinant จะเปน 0 เนื่องจากวาเราไมสามารถหาคาของ square root ของ 0 ได เราจะใชตวั เลขที่ทําใหคาของ b2 – 4ac เปนบวกเทานั้นเพื่อหลีกเลี่ยงเหตุการณดังกลาว อีกอยางหนึง่ ก็คือ เรายังไมไดเรียนเรื่องการใช ชุดคําสั่ง ในการตรวจสอบ (if –else) เราจะกลับมาดูตัวอยางนี้อีกครั้งหนึ่งเมื่อเราไดเรียนเรื่องของการใช ชุดคําสั่ง ในการตรวจสอบ ในที่นี้เราสนใจแตเรื่องของการใช Math.sqrt() เทานั้นเอง เรามาลองใช Mathematical function อื่น ๆ ดูกันดีกวา /* MaxMin.java - Finding max and min */ class MaxMin { public static void main(String[] args) { int num1 = 58, num2 = 97, num3 = 15; //finding maximum between num1, num2, and num3 int maxOfTwo = Math.max(num1, num2); int maxOfAll = Math.max(maxOfTwo, num3); //finding minimum between num1, num2, and num3 int minOfTwo = Math.min(num1, num2); int minOfAll = Math.min(minOfTwo, num3);

}

}

System.out.println("Maximum number is " + maxOfAll); System.out.println("Minimum number is " + minOfAll);

โปรแกรม MaxMin.java แสดงการเรียกใช method max() และ min() ในการเปรียบเทียบและหาคาที่ มากทีส ่ ุด และคาที่นอยทีส ่ ด ุ ของ integer 3 ตัว ตามลําดับ และเนื่องจากวา method ทั้งสองยอมรับ parameter เพียงแคสองตัวเทานั้น เราจึงตองทําการหาคาสองครั้ง ครั้งแรกระหวาง integer 2 ตัวแรก และครั้งที่สองระหวางคาทีห ่ าได กับ integer ที่เหลือ และเมือ ่ execute โปรแกรมเราก็จะไดผลลัพธดังที่ เห็นนี้ Maximum number is 97

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

41

Minimum number is 15 โปรแกรมที่แสดงใหดูตอไปนี้เปนโปรแกรมที่เรียกใช method ตาง ๆ ที่มีอยูใ น class Math /* Maths.java - Other math functions */ class Maths { public static void main(String[] args) { double angle = 0.7853982; //45 degrees angle in radians System.out.println("sin(45) is " + Math.sin(angle)); System.out.println("cos(45) is " + Math.cos(angle)); System.out.println("tan(45) is " + Math.tan(angle));

}

}

//absolute value of -456 System.out.println("Absolute value of -456 is " + Math.abs(-456)); //two to the fourth power System.out.println("2 to the 4th power is " + Math.pow(2D, 4D)); //round to the nearest integer System.out.println("2.345267 rounded to " + Math.round(2.345267)); //round to the nearest integer System.out.println("2.859 rounded to " + Math.round(2.859)); //the remainder of 3.25 / 2.25 System.out.println("The remainder of 3.25 / 2.25 is " + Math.IEEEremainder(3.25, 2.25)); //nearest integer of PI System.out.println("The nearest integer of PI is " + Math.rint(Math.PI));

โปรแกรม Maths.java ใช method จาก class Math ทําการหาคาของ sine cosine และ tangent ของ มุม 45 ซึ่งมีคาเทากับ 0.7853982 radians สาเหตุทต ี่ องใชมุมที่เปน radians ก็เพราะวา method เหลานี้ บังคับใหมุมทีร่ บ ั เขาเปน parameter มีชนิดเปน radians หลังจากนั้นก็ทาํ การหาคา absolute ของ -456 คา 24 และคาการปดเศษในรูปแบบตาง ๆ ผลลัพธที่ได จากการ run คือ sin(45) is 0.7071068070684596 cos(45) is 0.7071067553046345 tan(45) is 1.0000000732051062 Absolute value of -456 is 456 2 to the 4th power is 16.0 2.345267 rounded to 2 2.859 rounded to 3 The remainder of 3.25 / 2.25 is 1.0 The nearest integer of PI is 3.0 โปรแกรมตัวอยางการใช method toRadians() สําหรับการเปลี่ยนมุมที่เปน degrees ใหเปน radians ถา เราไมรูวามุมที่เราเคยชินอยูด  วยการวัดแบบ degrees มีคาเปนเทาไรในการวัดแบบ radians /* Maths1.java - Other math functions */ import java.text.DecimalFormat; class Maths1 {

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

42

public static void main(String[] args) { double angle = 45; //45 degrees angle double sin, cos, tan; //set format output DecimalFormat f = new DecimalFormat("0.00000"); //calculate sin, cos, and tan sin = Math.sin(Math.toRadians(angle)); cos = Math.cos(Math.toRadians(angle)); tan = Math.tan(Math.toRadians(angle)); System.out.println("sin(" + angle + ") = " + f.format(sin)); System.out.println("cos(" + angle + ") = " + f.format(cos)); System.out.println("tan(" + angle + ") = " + f.format(tan)); }

}

โปรแกรมตัวอยางอีกตัวหนึ่งทีใ่ ช math function ในการคํานวณหาคาของรัศมีของวงกลม จากพื้นที่ของ วงกลมที่กําหนดให /* Radius.java - Other math functions */ import java.text.DecimalFormat; class Radius { public static void main(String[] args) { double radius; double area = 850.0; int meters, centimeters; //calculate radius radius = Math.sqrt(area / Math.PI); //convert to meters and centimeters meters = (int)Math.floor(radius); centimeters = (int)Math.round(100.0 * (radius - meters));

}

}

System.out.print("Circle with area of " + area + " square meters "); System.out.print("has a radius of " + meters + " meters and "); System.out.println(centimeters + " centimeters");

เราใช floor() ในการหาคาของรัศมีที่เปนจํานวนเต็ม และใช round() ในการคํานวณหาคาของ centimeters ที่เหลือจากการนําเอา meters ไปลบออกจาก radius ซึ่งเมื่อ run ก็จะไดผลลัพธดังนี้ Circle with area of 850.0 square meters has a radius of 16 meters and 45 centimeters ยังมี method อีกหลายตัวทีผ ่ เู ขียนโปรแกรมอาจตองใช ซึ่งไดสรุปไวในตารางที่ 2.6 ตาราง 2.6 Mathematical Functions สําหรับการหาคาทางตรีโกณ Method Function Argument sin(arg) หาคา sine double (radians) cos(arg) หาคา cosine double (radians) tan(arg) หาคา tangent double (radians)

Result Type double double double

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

43

asin(arg)

หาคา arc sine

double

acos(arg)

หาคา arc cosine

double

atan(arg)

หาคา arc tangent

double

atan2(arg1, arg2)

หาคา arc tangent of arg1 และ arg2

double

abs(arg)

หาคา absolute ของ arg

max(arg1, arg2)

หาคาสูงสุดระหวาง arg1 และ arg2 หาคาต่ําสุดระหวาง arg1 และ arg2 หาคาที่เล็กทีส ่ ด ุ ทีใ่ หญกวา หรือเทากับ arg หาคาที่ใหญทส ี่ ุดที่นอยกวา หรือเทากับ arg หาคา integer ที่ใกลเคียงกับ arg ทีส ่ ุด

int long float double int long float double int long float double double

double (radians ระหวาง – π /2 และ π /2) double (radians ระหวาง 0.0 และ π) double (radians ระหวาง – π /2 และ π /2 ) double (radians ระหวาง – π และ π) เหมือนกันกับ Argument เหมือนกันกับ Argument เหมือนกันกับ Argument double

double

double

float double

double

ได int ถา argument เปน float และ long ถา เปน double double

double

double

double double

double double

double double ไมมี

double double double

min(arg1, arg2) ceil(arg) floor(arg) round(arg)

rint(arg) IEEEremainder(arg1, arg2) sqrt(arg) pow(arg1, arg2) exp(arg) log(arg) random()

หาคา integer ที่ใกลเคียงกับ arg ทีส ่ ุด หาคาเศษที่เหลือจากการหาร arg1 ดวย arg2 หาคา root ทีส ่ องของ arg หาคาของ arg1 ยกกําลัง arg2 หาคา e ยกกําลัง arg หาคา log ของ arg หาคาสุมที่มากกวา 0.0 แต นอยกวา 1.0

การใชขอ  มูลที่เปน Character เราไดดูการประกาศตัวแปรที่เปน character มากอนหนานี้เพียงตัวอยางเดียว เพื่อใหเกิดความเขาใจถึง การใชขอมูลที่เปน character ใน Java เรามาลองดูตัวอยางการใช character ในรูปแบบตาง ๆ กันอีกสัก หนอย /* Characters.java - Using character data */ class Characters { public static void main(String[] args) { char H, e, l, o; H e l o

= = = =

72; 101; 108; 111;

//ASCII //ASCII //ASCII //ASCII

for for for for

'H' 'e' 'l' 'o'

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

}

ขอมูล ตัวแปร และ การประมวลผล

44

System.out.print(H); System.out.print(e); System.out.print(l); System.out.print(l); System.out.print(o); System.out.println(" World");

}

ผลลัพธจากการ run โปรแกรม Characters.java ก็คือ Hello World ซึ่งตัวโปรแกรมเองใชรหัส ASCII ใน การกําหนดคาใหกับตัวแปร H e l และ o ซึ่งเมื่อนําไปแสดงผลก็จะไดคาทีต ่ ัวแปรเหลานั้นเปนอยู เรามา ลองดูการประมวลผลดวยการใช character ดวย operator งาย ๆ ที่มีอยู /* Characters1.java - Using character data */ class Characters1 { public static void main(String[] args) { char ch1 = 88, ch2 = 77; System.out.println("ch1 = " + ch1); System.out.println("ch2 = " + ch2); ch1 -= 23; //ASCII for 'A' ch2 += 6; //ASCII for 'S'

}

System.out.println("ch1 = " + ch1); System.out.println("ch2 = " + ch2);

}

โปรแกรมเริม ่ ตนดวยการกําหนดคาให ch1 และ ch2 มีคาเปนตัวอักษร X และ M ตามลําดับ และเมื่อ แสดงผลของทัง้ สองตัวแปรแลว โปรแกรมก็เปลี่ยนคาใหกับตัวแปร ch1 และ ch2 ดวยการลดคาของ ch1 ลงเปนจํานวนเทากับ 23 และเพิ่มคาใหกับตัวแปร ch2 อีก 6 เพื่อใหไดตัวอักษร A และ X และเมื่อ execute โปรแกรมเราก็จะไดผลลัพธทั้งหมดเปน ch1 ch2 ch1 ch2

= = = =

X M A S

ทีนี้เรามาลองดูการใช Unicode ในการแสดงผลตัวอักษรตาง ๆ /* Characters2.java - Using character data */ class Characters2 { public static void main(String[] args) char ch1 = '\u0058'; //unicode for char ch2 = '\u004D'; //unicode for char ch3 = '\u0041'; //unicode for char ch4 = '\u0053'; //unicode for

}

System.out.println("ch1 System.out.println("ch2 System.out.println("ch3 System.out.println("ch4

= = = =

" " " "

+ + + +

{ 'X' 'M' 'A' 'S'

ch1); ch2); ch3); ch4);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

45

} ซึ่งเมื่อ run แลวก็จะไดผลลัพธเหมือนกันกับผลลัพธของโปรแกรม Characters1.java เราสามารถทีจ ่ ะใช Unicode ในการแสดงตัวอักษรในภาษาไทยได เชนเดียวกันกับที่เราใช Unicode ใน การแสดงตัวอักษรในภาษาอังกฤษ แตวาระบบของเราจะตองเอื้อตอการแสดงผลที่เปนตัวอักษรไทยดวย ไมเชนนั้นแลวผลลัพธที่ไดก็จะเปนตัวอักษรที่อานไมรูเรื่อง หรือไมก็แสดงผลเปนเครื่องหมาย '?' ทุกตัว แตถา เราใช Unicode เพื่อการแสดงผลใน applet เราก็จะไมเจอปญหาใด ๆ เลยเพราะ Unicode ไดถูก ออกแบบมาเพื่อแสดงผลบน applet อยูแลว ตารางที่ 2.7 แสดงถึงตัวอักษรทีใ่ ชในการแสดงผลลัพธที่ไมใชตวั อักษรธรรมดา หรือทีภ ่ าษาอังกฤษ เรียกวา Character Escape Sequences ซึ่งเราสามารถนํามาใชในการจัดวางรูปแบบของผลลัพธที่เรา ตองการใหดูแลวสวยงามขึ้น (อยางหยาบ ๆ และ งาย ๆ) ตาราง 2.7 Character Escape Sequence Escape Sequence ความหมาย \ddd แสดงผลลัพธเปนเลขฐานแปด (Octal) \uxxxx แสดงตัวอักษร Unicode (Hexadecimal) \' ตัว ' (Single quote) \" ตัว " (Double quote) \\ ตัว \ เอง \r กลับไปยังจุดเริม ่ ตนของบรรทัด (Carriage return) \n ขึ้นบรรทัดใหม (New line หรือ Linefeed) \f เลื่อนไปหนาถัดไป (Form feed) \t เลื่อนไปยังตําแหนงถัดไป (Tab) \b เลื่อนไปทางซายหนึ่งตัวอักษร การใชตัวแปรชนิด boolean เราไดเห็นการประกาศตัวแปรทีเ่ ปน boolean มาเพียงนอยนิดกอนหนานี้ ตอไปเราจะมาทําความเขาใจกับ ขอมูลที่เปน boolean และการประมวลตัวแปรหรือประโยคทีม ่ ีคาของการประมวลผลเปน boolean อีกสัก เล็กนอยกอนที่เราจะใชมันในโอกาสตอไป ผูเขียนหลายทานเรียก operator เหลานี้วา Logical Operator โดยทั่วไปเราสามารถประมวลผลขอมูลที่เปน boolean ดวย operator ตาง ๆ ที่เห็นนี้ && || & | !

หรือที่เรียกวา หรือที่เรียกวา หรือที่เรียกวา หรือที่เรียกวา หรือที่เรียกวา

Conditional AND Conditional OR Logical AND Logical OR Logical NOT

&& และ || มีการประมวลผลในรูปแบบที่หนังสือหลาย ๆ เลมใหชื่อวา Lazy หรือ Short Circuit ซึ่งมี รูปแบบการประมวลผลทีแ ่ ตกตางจาก & และ | operator && ตางจาก & โดยที่ && นั้นจะไมประมวลผล ประโยคหรือตัวแปรทีต ่ ามหลังตัวมันเอง ถา ประโยคหรือตัวแปรที่อยูกอนหนามีคาเปน false เพราะวาคาที่เปน false เมื่อนํามาประมวลผลกับคาอื่น ๆ แลวจะได false เสมอ operator || ก็เชนเดียวกันกับ && แตจะประมวลผลประโยคหรือตัวแปรที่ตามมาเมื่อประโยคแรกหรือตัว แปรตัวแรกมีคาเปน true เพราะวาประโยคหรือตัวแปรที่มค ี าเปน true เมื่อนํามาประมวลกับคาใด ๆ ก็ตาม จะไดคา true เสมอ สวน operator & และ | จะประมวลผลประโยคและตัวแปรทัง้ สองเสมอ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

46

และ operator ! นั้นเมื่อไปอยูหนาตัวแปรหรือประโยคที่มค ี า ทาง boolean คาใดคาหนึ่งก็จะเปลี่ยนคานั้น ใหเปนตรงกันขามทันที Operator ตัวอืน ่ ๆ ที่ใชกับตัวแปรหรือประโยคที่มค ี าเปน boolean มีดังนี้ < ใชในการเปรียบเทียบวา > ใชในการเปรียบเทียบวา <= ใชในการเปรียบเทียบวา หรือไม >= ใชในการเปรียบเทียบวา หรือไม == ใชในการเปรียบเทียบวา != ใชในการเปรียบเทียบวา

คาทางดานซายของเครื่องหมาย นอยกวา คาทางดานขวาหรือไม คาทางดานซายของเครื่องหมาย มากกวา คาทางดานขวาหรือไม คาทางดานซายของเครื่องหมาย นอยกวาหรือเทากับ คาทางดานขวา คาทางดานซายของเครื่องหมาย มากกวาหรือเทากับ คาทางดานขวา คาทางดานซายของเครื่องหมาย เทากับ คาทางดานขวาหรือไม คาทางดานซายของเครื่องหมาย ไมเทากับ คาทางดานขวาหรือไม

เราเรียก operator เหลานี้วา Relational operator ซึ่งเอาไวใชในการตรวจสอบความสัมพันธของตัวแปร หรือประโยความีคาแตกตางกันอยางไรเมื่อนํามาเปรียบเทียบกัน เราจะลองเขียนโปรแกรมตรวจสอบ operator ตาง ๆ เหลานีด ้ ู /* BooleanOp.java - Testing boolean operations */ class BooleanOp { public static void main(String[] args) { boolean A = true, B = false;

}

}

System.out.println("Conditional System.out.println("F && F is " System.out.println("F && T is " System.out.println("T && F is " System.out.println("T && T is "

AND"); + (B && + (B && + (A && + (A &&

B)); A)); B)); A));

System.out.println("Conditional System.out.println("F || F is " System.out.println("F || T is " System.out.println("T || F is " System.out.println("T || T is "

OR"); + (B || + (B || + (A || + (A ||

B)); A)); B)); A));

System.out.println("Logical AND"); System.out.println("F & F is " + (B System.out.println("F & T is " + (B System.out.println("T & F is " + (A System.out.println("T & T is " + (A

& & & &

B)); A)); B)); A));

System.out.println("Logical OR"); System.out.println("F | F is " + (B System.out.println("F | T is " + (B System.out.println("T | F is " + (A System.out.println("T | T is " + (A

| | | |

B)); A)); B)); A));

System.out.println("Logical NOT"); System.out.println("!F is " + (!B)); System.out.println("!T is " + (!A));

โปรแกรมประกาศตัวแปรสองตัว A และ B ดวยคา true และ false ตามลําดับ และทําการแสดงผลลัพธ ของการประมวลผลดวย operator ผานทาง System.out.println() ผลลัพธที่แสดงออกทางหนาจอ คือ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

47

Conditional AND F && F is false F && T is false T && F is false T && T is true Conditional OR F || F is false F || T is true T || F is true T || T is true Logical AND F & F is false F & T is false T & F is false T & T is true Logical OR F | F is false F | T is true T | F is true T | T is true Logical NOT !F is true !T is false ทีนี้ลองมาดูโปรแกรมการใช Relational operator /* BooleanOp2.java - Using relational operators */ class BooleanOp2 { public static void main(String[] args) { int i = 5, j = 10;

}

}

System.out.println("i = " + i); System.out.println("j = " + j); System.out.println("i > j is " + (i > j)); System.out.println("i < j is " + (i < j)); System.out.println("i >= j is " + (i >= j)); System.out.println("i <= j is " + (i <= j)); System.out.println("i == j is " + (i == j)); System.out.println("i != j is " + (i != j)); System.out.println("(i < 10) && (j < 10) is " + ((i < 10) && (j < 10))); System.out.println("(i < 10) || (j < 10) is " + ((i < 10) || (j < 10)));

โปรแกรม BooleanOp2.java ทําการหาคาของประโยคตาง ๆ ในรูปแบบงาย ๆ เพื่อใหผูอา นไดเห็นถึง ผลลัพธของการใช operator ตาง ๆ ไดอยางชัดเจน เราประกาศตัวแปรที่เปน int สองตัว คือ i และ j ซึ่ง กําหนดใหมีคาเปน 5 และ 10 ตามลําดับ หลังจากนั้นโปรแกรมก็ใช operator ตาง ๆ กับตัวแปรสองตัวนี้ และเมื่อ run โปรแกรมนีแ ้ ลวผลลัพธที่ได คือ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

48

i = 5 j = 10 i > j is false i < j is true i >= j is false i <= j is true i == j is false i != j is true (i < 10) && (j < 10) is false (i < 10) || (j < 10) is true เพื่อใหเห็นภาพของการประมวลของ operator && และ operator || ไดชด ั เจนยิ่งขึ้น ผูอา นควร ตรวจสอบจากแผนภาพของการประมวลผลนี้ โดยเราไดกําหนดใหตัวแปร p และ q มีคาเปน 5 และ 10 ตามลําดับในการประมวลผลทางดานซาย และใหมค ี าเปน 10 และ 5 ในการประมวลผลทางดานขวา p = 5, q = 10

(p < q)

&&

T

p = 10, q = 5

(q <= 10)

(p < q)

T

F

&&

(q <= 10)

ไมตองประมวลตอเพราะ F && กับอะไรก็ได F

T ภาพที่ 2.4 การประมวลผลดวย &&

p = 5, q = 10

(p < q)

T

||

p = 10, q = 5

(q <= 10)

ไมตองประมวลผลตอเพราะ T || กับ อะไรก็ได T

(p < q)

||

F

(q <= 10)

T

T

ภาพที่ 2.5 การประมวลผลดวย ||

ตาราง 2.8 ไดสรุปคาของการประมวลผลดวย operator && || & | ดังที่ไดกลาวมาแลว

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ตาราง 2.8 P true false true false

ขอมูล ตัวแปร และ การประมวลผล

การใช operator && || & และ | Q P && Q P || Q true true true true false true false false true false false false

P&Q true false false false

49

P|Q true true true false

เราคงมองไมเห็นถึงประโยชนของการใชตวั แปรที่เปน boolean และการใช operator ตาง ๆ ที่ไดพูดถึง ในตอนนี้อยางมากมายนัก การประมวลผลของตัวแปรที่เปน boolean สวนใหญจะเอาไวชว ยการตรวจสอบ ถึงเหตุการณ (condition) ตาง ๆ ที่อาจเกิดขึ้นในโปรแกรม เชน ถาประโยคที่หนึ่ง เมื่อนํามาประมวลผล กับ ประโยคทีส ่ องแลว ผลลัพธที่ไดเปน true หรือ false ซึ่งถาเปน true เราจะทําการอยางอื่น และก็จะ ทําการอื่นหากเปน false เปนตน เราจะพูดถึง boolean operator ตาง ๆ เมื่อเราพูดถึงเรื่องของ logic และเรื่องของการประมวลผลในรูปแบบของการวนซ้ํา (logic and loop) การประมวลผลในระดับ bit ดวยการใช operator Shift และ Bitwise ในการทํางานในระดับ bit นั้นมี operator ไมกี่ตัวที่เราสามารถเรียกใชได ซึ่งการใชงานโดยทั่วไปก็ไมงาย นัก เพราะตองทําในระดับ bit และผูใชตองมีความเขาใจในเรื่องของเลขฐานสองอยางดีพอสมควร เราจะ ยกตัวอยางเพียงไมกี่ตัวอยางเพื่อใหเห็นถึงการใชงานของ operator shift ตาง ๆ ที่ Java มีให คือ << >> และ >>> ตาราง 2.9 การใช operator shift << >> และ >>> Operator วิธีใช ความหมาย << operand1 << operand2 โยก bit ของ operand1 ไปทางซายจํานวนเทากับคาของ operand2 เติม 0 ทุก ๆ bit ทางขวา >> operand1 >> operand2 โยก bit ของ operand1 ไปทางขวาจํานวนเทากับคาของ operand2 เติมดวยคา bit (sign bit)สูงสุดทางซาย >>> operand1 >>> operand2 โยก bit ของ operand1 ไปทางขวาจํานวนเทากับคาของ operand2 เติม 0 ทุก ๆ bit ทางซาย ตัวอยาง 13 >> 1 13 = 000011012 เมื่อ shift ไปทางขวา 1 bit ผลลัพธที่ไดคือ 000001102 (เทากับ 6 ในเลขฐาน 10) 13 << 1 shift ไปทางซาย 1 bit ผลลัพธที่ไดคือ 000110102 (เทากับ 26 ในเลขฐาน 10) 13 >>> 1 shift ไปทางขวา 1 bit ผลลัพธที่ไดคือ 000001102 (เทากับ 6 ในเลขฐาน 10) การโยก bit ไปทางซายครั้งละหนึ่ง bit นั้นที่จริงแลวก็คือการคูณดวยสอง เรามาดูตวั อยางโปรแกรมการ โยก bit ไปทางซายกัน จากโปรแกรม ShiftLeftOp.java ที่เห็นดานลางนี้ /* ShiftLeftOp.java - Using shift operators */ class ShiftLeftOp { public static void main(String[] args) { byte bits = 1; System.out.println("Value of bits is " + bits); bits = (byte) (bits << 1); System.out.println("Value of bits is " + bits); bits = (byte) (bits << 1);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

}

}

ขอมูล ตัวแปร และ การประมวลผล

System.out.println("Value of bits = (byte) (bits << 1); System.out.println("Value of bits = (byte) (bits << 1); System.out.println("Value of bits = (byte) (bits << 1); System.out.println("Value of

50

bits is " + bits); bits is " + bits); bits is " + bits); bits is " + bits);

เราเริ่มดวยการกําหนดใหตัวแปร bits มีชนิดเปน byte และมีคาเทากับหนึ่ง โปรแกรมทําการโยก bit ไป ทางซายจํานวนเทากับหาครั้ง ซึ่งในการโยกแตละครั้งเราก็จะไดคา ใหมทม ี่ ีคาเทากับคาเดิมคูณดวยสอง ดังที่เห็นจากผลลัพธของการ run โปรแกรมนี้ Value Value Value Value Value Value

of of of of of of

bits bits bits bits bits bits

is is is is is is

1 2 4 8 16 32

เราเลือกใชขอมูลชนิดที่เปน byte ก็เพื่อใหเห็นวาถาเราโยก bit อีกครั้งดวยจํานวน bit ที่ตองการโยก เทากับสอง bit (ครั้งที่หก) เราจะไดคาทีต ่ ัวแปร bits ไมสามารถเก็บได ลองดู code ที่เพิ่ม และ ผลลัพธ ของการ run bits = (byte) (bits << 2); System.out.println("Value of bits is " + bits); ผลลัพธเมื่อ run อีกครั้งดวย code ที่เพิ่มขึ้นจะเห็นวาคาของ bits ที่ไดมีคาเปน -128 ซึ่งเปนคาที่ Java เปนผูกําหนดให แตไมใชคา ที่ถูกตอง เพราะขอมูลที่เปน byte นั้นเก็บคาสูงสุดที่เปนบวกไดเพียงแค 127 เทานั้น Value Value Value Value Value Value Value

of of of of of of of

bits bits bits bits bits bits bits

is is is is is is is

1 2 4 8 16 32 -128

สิ่งสําคัญอีกสิ่งหนึ่งก็คือ การ cast เราจําเปนตองเปลี่ยนขอมูลใหถูกตองตามชนิดของตัวแปร เนื่องจากวา Java ไดทําการเปลี่ยนตัวแปร bits ของเราใหเปน int กอนที่จะทําการ shift ดังนั้นเราตองเปลี่ยนขอมูลให กลับมาเปนชนิดเดิมกอนการจัดเก็บ (หลังจากการ shift สิ้นสุดลง) เราไดพูดถึงการประกาศตัวแปร การกําหนดคาใหกับตัวแปรที่อยูภายในตัวโปรแกรม ดวยขอมูลทั้งที่มีชนิด เปน integer และ floating-point ซึ่งการกําหนดคาใหกับตัวแปรภายในโปรแกรมนั้น ไมมีความยืดหยุน ของขอมูลที่ถูกเก็บอยูในตัวแปรนั้น หากผูใช หรือ ผูเขียนโปรแกรมตองการที่จะเปลีย ่ นคาที่ตัวแปรนั้นเก็บ อยู ผูเขียนจะตองเปนผูแกไขแตเพียงฝายเดียว ผูใ ชโปรแกรมไมสามารถทีจ ่ ะเปลี่ยนคาเหลานั้นได ดังนั้น การเขียนโปรแกรม จะตองใหโอกาสผูใ ชโปรแกรมในการเปลี่ยนแปลงคาเหลานั้น Java มี method อยู หลายตัวที่รองรับการใสขอมูลผานทาง keyboard เราจะมาทําความรูจ  ัก และเขาใจถึงวิธก ี าร ซึ่งคอนขาง จะซับซอนพอสมควรสําหรับผูเริ่มหัดเขียนโปรแกรมใหม อยางไรก็ตามหลังจากที่ไดทําความเขาใจแลว ก็ จะเห็นวาการรับคาตาง ๆ ผานทาง keyboard นั้นเปนเรื่องที่ (จริง ๆ แลว) ไมยุงยากเลย

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

51

การกําหนดคาใหกับตัวแปรผานทางสือ ่ การนําเขาขอมูลมาตรฐาน Java ไมมี method ใด ๆ ที่รับคาขอมูลตามชนิดนั้น ๆ ของขอมูลที่เขามาเลย เชน ถาผูใชโปรแกรม ตองการทีจ ่ ะใสคาที่เปน int float double หรือ char ผูเขียนโปรแกรมก็ไมสามารถทีจ ่ ะรับคาตาง ๆ เหลานี้ไดโดยตรง เหมือนกับการเขียนโปรแกรมดวยภาษาอื่น ๆ เชน C หรือ C++ แตตัวผูเขียนเองจะตอง เขียน code ขึ้นมารองรับคาเหลานี้ผานทางการอานเขาแบบที่เรียกวา การรับขอมูลที่เปน String ซึ่งเมื่อ อาน String ไดแลวก็ตองแปลง String ใหเปนชนิดของขอมูลทีผ ่ ูเขียนโปรแกรมตองการใหเปน ผูอานอาจสงสัยวา String คืออะไร ในที่นจ ี้ ะอธิบายอยางคราว ๆ เนื่องจากวาเราจะพูดถึง String ในบท อื่นตอไป ใน Java นั้น String เปน object (อีกแลว object? เชนเดียวกันเราจะพูดถึง object อยาง ละเอียดในบทอื่น) ซึ่งสามารถเก็บตัวอักษรไดคราวละมาก ๆ ขอยกตัวอยางงาย ๆ ใหดูกแ ็ ลวกัน People of Thailand สวัสดี price_of_coffee 1234567890 23+popOfRock ตัวอยางที่เห็นดานบนนี้ลวนแลวแตเปน String ทั้งนั้น ทีนี้เรามาลองดูวิธีการอาน String เขามาจาก keyboard แลวก็เปลี่ยน String ใหเปนขอมูลชนิดตาง ๆ ที่เราตองการ เริ่มดวยการเปลีย ่ นแปลง code ของโปรแกรม Radius.java ใหรับคาของ area จาก keyboard แทนการกําหนดภายในโปรแกรม /* Radius2.java - Reading data from keyboard */ import java.io.*; class Radius2 { public static void main(String[] args) throws IOException { double radius, area; int meters, centimeters; //prompt user for area of a circle System.out.print("Please enter area of a circle: "); //get string from keyboard InputStreamReader in = new InputStreamReader(System.in); BufferedReader buffer = new BufferedReader(in); String inputString = buffer.readLine(); //convert string to double area = Double.parseDouble(inputString); //calculate radius radius = Math.sqrt(area / Math.PI); //convert to meters and centimeters meters = (int)Math.floor(radius); centimeters = (int)Math.round(100.0 * (radius - meters));

}

}

System.out.print("Circle with area of " + area + " square meters "); System.out.print("has a radius of " + meters + " meters and "); System.out.println(centimeters + " centimeters");

โปรแกรม Raadius2.java เพิ่ม code ใหอาน String จาก keyboard ดวยประโยค System.out.print("Please enter area of a circle: ");

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

52

InputStreamReader in = new InputStreamReader(System.in); BufferedReader buffer = new BufferedReader(in); String inputString = buffer.readLine(); ประโยคแรกสุดเปนการสงขอความไปยัง user ใหรูวาตองใสขอมูลอะไรเขาสูโปรแกรม ประโยคถัดมาอาน ขอมูลในรูปแบบของ byte จากระบบ (System.in) เปลี่ยนขอมูลเหลานั้นใหเปน character แลวจึงนํามา เก็บไวในตัวแปร in ประโยคทีส ่ ามทําการจองเนื้อที่ใหกับตัวแปร buffer พรอมกับนําคา character ที่อยู ในตัวแปร in มาเก็บไวในรูปแบบของ String เมื่อได String (ซึ่งตอนนี้อยูในตัวแปร buffer) เราก็ทําการ อาน String ที่วา นี้ดวย method readLine() ผานทางตัวแปร buffer แลวจึงนําไปเก็บไวในตัวแปรชนิด String ที่มีชื่อวา inputString ฟงดูแลวรูส  ึกวามีขั้นตอนมากมายในการอาน String แตตอนนี้ขอเพียงแตจาํ วาถาจะอาน String จาก keyboard ตองทําดวยวิธีนี้ (ณ เวลานี้ เพราะมีอีกหลายวิธี) เมื่อเราได String แลวขั้นตอนตอไปก็คือการเปลี่ยน String ใหเปนขอมูลชนิดที่เราตองการใชในโปรแกรม ซึ่งโปรแกรม Radius.java ของเราตองการใชขอมูลชนิดที่เปน double เราจึงตองทําการเปลี่ยน String นี้ ใหเปน double ดวยการเรียกใช method parseDouble() จาก class Double พรอมทั้งสงตัวแปรที่เก็บ ขอมูลจาก keyboard ไปใหแก method นี้ดวย area = Double.parseDouble(inputString); หลังจากนั้น code ของโปรแกรมที่เหลือก็เหมือนกับที่เราไดเขียนกอนหนานี้ และเมื่อ run โปรแกรมดู สองครั้ง ดวยคา 850 ในครั้งแรกและคา 54 ในครั้งที่สอง เราก็ไดผลลัพธ ดังที่แสดงใหเห็นนี้ Please enter area of a circle: 850 Circle with area of 850.0 square meters has a radius of 16 meters and 45 centimeters Please enter area of a circle: 54 Circle with area of 54.0 square meters has a radius of 4 meters and 15 centimeters ถาสังเกตใหดจ ี ะเห็นวาโปรแกรม Radius2.java นั้นมีขอความเพิ่มตอทายของ main(..) คือ throws IOException เหตุผลที่เราตองเพิ่ม throws IOException ใหกับ main(…) ก็เพราะวา การอานขอมูลเขาสูโปรแกรมนั้น บางครั้งก็อาจเจอกับปญหาในการอาน เชน อานไมได และเหตุผลอีกอันหนึ่ง คือ Java บังคับใหเราตอง ตรวจสอบการทํางานกับ I/O เอง ซึ่งถาหากมีปญหาเกิดขึ้น เราจะไดแกไขไดถูกตอง มีวิธก ี ารตรวจสอบ และปองกันไมใหการอานมีปญหาหลากหลาย ซึ่งเราจะไดดูกน ั ในโอกาสตอไป (บทที่ 7) ลองมาดูวาถา เราไมใสขอความที่วาลงไปในโปรแกรม Radius2.java เราจะได error อะไร Radius2.java:16: unreported exception java.io.IOException; must be caught or declared to be thrown String inputString = buffer.readLine(); ^ 1 error จะเห็นวา Java จะบอกใหเรารูว าเราไมสามารถทีจ ่ ะอานขอมูลเขาสูโปรแกรมได ถาเราไมทําการตรวจสอบ ดวยวิธท ี ี่ไดกลาวไว ประโยคที่วา

must be caught or declared to be thrown กลาวถึงวิธี สองวิธี ที่เราสามารถใชไดในการอานขอมูลเขาสูโปรแกรม คือ (1) ตรวจจับ – catch และ (2) เรียกใช throws ของ Java

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

53

ตอไปจะไดแสดงการใชวิธท ี ี่หนึ่ง ซึ่งเปนการตรวจจับ error ในการอานขอมูล แตจะพูดเพียงเพื่อใหการ อานขอมูลทําไดสมบรูณเทานัน ้ คงจะไมกลาวถึงอยางละเอียดมากมายนัก เรามาเริ่มตนดวยการเขียน code เพิ่มขึ้นใหม ดังที่แสดงใหเห็นนี้ /* Radius2.java - Reading data from keyboard */ import java.io.*; class Radius2 { public static void main(String[] args) throws IOException { double radius, area; int meters, centimeters; String inputString = null; try { //prompt user for area of a circle System.out.print("Please enter area of a circle: "); //get string from keyboard InputStreamReader in = new InputStreamReader(System.in); BufferedReader buffer = new BufferedReader(in); inputString = buffer.readLine(); } catch(IOException ioe) {} //convert string to double area = Double.parseDouble(inputString); //calculate radius radius = Math.sqrt(area / Math.PI); //convert to meters and centimeters meters = (int)Math.floor(radius); centimeters = (int)Math.round(100.0 * (radius - meters));

}

}

System.out.print("Circle with area of " + area + " square meters "); System.out.print("has a radius of " + meters + " meters and "); System.out.println(centimeters + " centimeters");

สิ่งที่เราไดปรับปรุงคือประโยค ตอไปนี้ String inputString = null; //prompt user for area of a circle System.out.print("Please enter area of a circle: "); try { //get string from keyboard InputStreamReader in = new InputStreamReader(System.in); BufferedReader buffer = new BufferedReader(in); inputString = buffer.readLine(); } catch(IOException ioe) {} เรายายการประกาศตัวแปร inputString ไปอยูก  อนประโยคทีอ ่ านขอมูลเขาพรอมกับเพิ่มประโยค try { …

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

54

… …

} catch(IOException ioe) {} เขาสูโปรแกรมดวยการนําเอาประโยคการอานขอมูลเขาสู string ทั้งสามประโยคไวใน block ของ try {} สวนคําวา catch(IOException ioe) {} นั้นเราก็เพิ่มเขาหลังจาก block ของ try {} เราไมจําเปนตองใส code อะไรเขาไปใน code ของ catch(IOExcpetion ioe) {} เพราะเราเพียงแตตองการใหการอาน เปนไปไดดวยดีเทานั้น เรายังจะไมกังวลถึง error ที่เกิดขึ้น ซึง่ ถามี error เกิดขึ้น Java ก็จะเปนผูฟองให เราทันที เพื่อใหเกิดความเขาใจอีกสักหนอย เราจะมาตรวจสอบการใสขอมูลของผูใชดูวา ไดมีการใสขอมูลเขาสู โปรแกรม หรือเพียงแตกดปุม Enter เฉย ๆ เราทําการตรวจสอบดวยการเพิ่ม try {..} และ catch() {} ใหกับโปรแกรม Radius2.java ดังนี้ /* Radius2.java - Reading data from keyboard */ import java.io.*; class Radius2 { public static void main(String[] args) { double radius, area; int meters, centimeters; String inputString = null; //prompt user for area of a circle System.out.print("Please enter area of a circle: "); try { //get string from keyboard InputStreamReader in = new InputStreamReader(System.in); BufferedReader buffer = new BufferedReader(in); inputString = buffer.readLine(); try { //convert string to double area = Double.parseDouble(inputString); //calculate radius radius = Math.sqrt(area / Math.PI); //convert to meters and centimeters meters = (int)Math.floor(radius); centimeters = (int)Math.round(100.0 * (radius - meters)); System.out.print("Circle with area of " + area + " square meters "); System.out.print("has a radius of " + meters + " meters and "); System.out.println(centimeters + " centimeters");

} //catch empty string (user hits Enter) catch(Exception e) { System.out.println("Error! you must supply input"); e.printStackTrace(); System.exit(1); }

}

} //catch other I/O error - do nothing catch(IOException ioe) { /* leave it to Java! */ }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

55

} โปรแกรม Radius2.java ที่เราเขียนขึ้นใหมมี try {…} และ cath() {} อยูสองตัว ตัวแรกใชตรวจสอบ เรื่องของการอานทั่วไปที่ไดกลาวไปแลว สวนตัวทีส ่ องเปนการตรวจสอบวาผูใชมีการใสขอมูลหรือไม ซึ่ง ถาไมใส เราก็จะ 1. สงขอความไปยังหนาจอดวยคําสั่ง System.out.println("Error! you must supply input"); 2. สงขอความ error ที่ Java ไดฟองไว ดวยคําสั่ง e.printStackTrace(); 3. ออกจากโปรแกรมโดยไมมีการประมวลผลใด ๆ ทั้งสิ้น ดวยคําสั่ง System.exit(1); และเมื่อ execute ดูเราก็จะไดขอความดังนี้ Please enter area of a circle: < ผูใชกดปุม  Enter > Error! you must supply input java.lang.NumberFormatException: empty String at java.lang.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:9 86) at java.lang.Double.parseDouble(Double.java:202) at Radius2.main(Radius2.java:22) โดยทั่วไปการออกจากโปรแกรมที่ไมมีปญหาใด ๆ ในการเขียนดวยภาษา Java นั้นเราจะใชการออกดวย เลข 1 ในประโยค System.exit(1) หรือเลขอื่น ๆ ที่ไมใช 0 สวนการออกแบบปกตินั้นเราใชเลข 0 แทน เลข 1 เราคงจะพักการตรวจสอบ หรือ ตรวจจับ error ไวเพียงแคนี้กอนเราจะกลับมาพูดถึงการเขียน code รองรับ error ในบทอื่นตอไป สรุป เราไดเรียนรูถึงขอมูลชนิดตาง ๆ ที่เปนขอมูลแบบพื้นฐาน หรือที่เรียกวา primitive datatype ที่ Java มี ให รวมไปถึงการประกาศตัวแปร การกําหนดคาใหกับตัวแปร การประมวลตัวแปรชนิดเดียวกัน และ ตาง ชนิดกัน การเปลี่ยนชนิดของขอมูล (casting) การใช method ที่เกี่ยวของกับตัวเลข การแสดงผลตัวเลข ที่มีจด ุ ทศนิยม การอานขอมูลเขาสูโปรแกรม และการตรวจสอบ และตรวจจับ error ที่อาจเกิดขึ้นในการ อานขอมูล แบบฝกหัด 1. จงอธิบายถึงความหมายของคําวา final พรอมทั้งยกตัวอยางประกอบ 2. จงอธิบายถึงความแตกตางระหวาง 5, 5.0, '5', "5", และ "5.0" 3. จงหาผลลัพธของการประมวลผลประโยคตอไปนี้ ถากําหนดให double x = 4.5; double y = -45.25; int p = 12; int q = 2; 3.1. 3.2. 3.3. 3.4. 3.5. 3.6.

x + p * y / (p – y) * x p % (p – q) (int) y (int) p Math.round(x) (int) Math.round(y)

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

3.7. 3.8. 3.9. 3.10.

ขอมูล ตัวแปร และ การประมวลผล

56

-2 * y + (int) x q/p p%q y * y – y + (x * (int) x)

4. จงเขียนโปรแกรมทีร่ ับตัวเลขชนิด int จาก keyboard จํานวน 2 ตัว และขอมูลชนิด double อีก 2 ตัว หลังจากนั้นใหโปรแกรมคํานวณหาผลรวมของเลขทั้ง 4 ตัว ใหเก็บผลลัพธที่หาไดไวในตัวแปรตัว ใหม สงผลลัพธที่ไดไปยังหนาจอ 5. จงเขียนประโยคดวยภาษา Java จากสมการที่ใหนี้ 5.1. 5.2. 5.3. 5.4.

a + bc / 2 a(a – c) + b(b – c) – (c(c – a) / d) b2 – 4ac (4/3)2 / 2

5.5.

 T xM  q= 1  + T2 D−k

6. จงเขียนโปรแกรมทีท ่ ําการเปลีย ่ น องศา Celsius ใหเปนองศา Fahrenheit โดยกําหนดใหขอมูลที่ ตองการเปลี่ยน นําเขาจาก keyboard โดยกําหนดใหสต ู รการเปลี่ยน คือ Celsius =

5 (Fahrenheit – 32) 9

7. จงเขียนโปรแกรมทีท ่ ําการเปลีย ่ น องศา Fahrenheit ใหเปนองศา Celsius โดยกําหนดใหขอมูลที่ ตองการเปลี่ยน นําเขาจาก keyboard 8. จงเขียนโปรแกรมทีร่ ับขอมูลทีเ่ ปนจํานวนกิโลกรัมจาก keyboard เปลี่ยนใหเปน mile สงผลลัพธไป ยังหนาจอ 9. จงเขียนโปรแกรมที่อานขอมูลจาก keyboard ที่เปนอายุของผูใชในรูปแบบของป ใหโปรแกรม เปลี่ยนเปนจํานวนวัน สงผลลัพธออกทางหนาจอ (กําหนดให 1 ปเทากับ 365 วัน) 10. จงเขียนโปรแกรมทีร่ ับ int จํานวน 5 ตัว หาคาเฉลี่ยของตัวเลขเหลานี้ เสร็จแลวสงผลลัพธไปยัง หนาจอ 11. จงเขียนโปรแกรมทีค ่ ํานวณหาเวลาที่แสงเดินทางจากโลกไปยังดวงอาทิตย ใหสงผลลัพธของการ คํานวณในรูปแบบของนาที สงผลลัพธที่หาไดไปยังหนาจอ 12. สมมติวาอาจารยทุกคนในวิทยาลัยแหงหนึ่งดืม ่ beer 1 ขวดตอวัน และในการทํา beer 1 ลัง (24 ขวด) นั้นตองใชขาว barley จํานวน 1 ถัง ถาจํานวนของอาจารยในวิทยาลัยที่วานี้มท ี ั้งสิ้น 200 คน จงเขียนโปรแกรมในการคํานวณหาจํานวนของขาว barley ที่ตองใชในการทํา beer ใหเพียงพอตอ การบริโภคของอาจารยในวิทยาลัยนี้ตลอดภาคการศึกษา 13. จงเขียนโปรแกรมทีร่ ับขอมูลชนิด long ที่มีจํานวนของตัวเลข (digit) อยูระหวาง 10 – 12 ตัว ใหสง ผลลัพธในรูปแบบของ ตัวเลขที่ใชเครื่องหมาย , เปนตัวแบงกลุม โดยเริ่มตนจากทางขวามือ และให มีตัวเลขกลุมละ 3 ตัวไปยังหนาจอ 14. จงเขียนโปรแกรมทีร่ ับคาความยาวของดานทุกดานของสามเหลี่ยม จากนั้นใหคํานวณหาคาของเสน รอบรูป (perimeter) สงผลลัพธไปยังหนาจอ 15. จงเขียนโปรแกรมทีค ่ ํานวณหาพื้นที่ของวงกลม จากรัศมีทรี่ ับเขามาจาก keyboard

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 2 เริ่มตนกับ Java

ขอมูล ตัวแปร และ การประมวลผล

57

16. จงเขียนโปรแกรมทีร่ ับขอมูลชนิด double จํานวน 5 ตัวจาก keyboard จากนั้นใหคํานวณหา คาเฉลีย ่ ของตัวเลขเหลานั้น สงผลลัพธที่หาไดไปยังหนาจอ 17. กําหนดใหเสนผาศูนยกลางของดวงอาทิตยเทากับ 865,000 ไมล และเสนผาศูนยกลางของโลก เทากับ 7,600 ไมล จงเขียนโปรแกรมที่คาํ นวณหา 17.1. 17.2. 17.3.

ปริมาตรของโลก (cubic mile หรือ mile3) ปริมาตาของดวงอาทิตย (cubic mile) อัตราสวนของปริมาตรของดวงอาทิตยตอปริมาตรของโลก

18. จงเขียนโปรแกรมทีร่ ับขอมูลชนิด double ที่อยูในรูปแบบ 123.4567 จาก keyboard จากนั้นใหดึง เอาสวนของขอมูลที่อยูห  นาจุดทศนิยมไปเก็บไวในตัวแปรที่มช ี นิดเปน long ตัวหนึ่ง เสร็จแลวใหเก็บ ขอมูลที่อยูหลังจุดทศนิยมไปเก็บไวในตัวที่เปน long อีกตัวหนึ่ง สงผลลัพธที่อยูในตัวแปร long ทั้ง สองไปยังหนาจอ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


ในบททีส ่ ามนี้เราจะมาทําความรูจักกับการทํางานในรูปแบบของการประมวลผลชุดคําสั่งซ้าํ ๆ กันตาม เงื่อนไขที่กําหนดให หรือที่เรียกวาการประมวลผลแบบวน (repetition หรือ loop) การใชชุดคําสั่งในการ ตัดสินใจ และ การใชประโยคในการเปรียบเทียบขอมูลตาง ๆ หลังจากจบบทเรียนนี้แลวผูอานจะไดทราบถึง o o o o

o

การเปรียบเทียบขอมูล (comparison) การกําหนดประโยคในการเปรียบเทียบ (logical expression) การเปลี่ยนแปลงขั้นตอนการประมวลผลในแบบตาง ๆ (control statement) การทํางานแบบวน (loop) for loop while loop do … while loop การยุติการทํางานของ loop ดวยการใชคาํ สั่ง break และ continue

หลาย ๆ ครั้งการเขียนโปรแกรมตองมีการเลือกที่จะประมวลผล ไมวาจะเปนการเลือกตามขอมูลที่นําเขา หรือ การเลือกประมวลผลตามขั้นตอน กระบวนการที่ไดกําหนดไว เชน ถาขอมูลนําเขามีคานอยกวาศูนย เราจะยุติการทํางานของโปรแกรม ถามากกวาเราจะมวลผลตอไป อะไรทํานองนี้ ในการตัดสินใจที่จะให code ทําอยางใด อยางหนึ่งนัน ้ เราจะตองรูจก ั วิธีการสรางประโยคทีใ่ ชในการเปรียบเทียบ ขั้นตอนของ การใชประโยคเปรียบเทียบในรูปแบบตาง ๆ การตัดสินใจ และ การเปรียบเทียบ การตัดสินใจเปนสวนประกอบที่สาํ คัญมาก ๆ สวนหนึ่งของการเขียนโปรแกรม โปรแกรมของเราตองมี ความสามารถในการตัดสินใจเลือกวาจะทําอะไรตอไป เชน ถาจํานวนของนักศึกษาที่มาสมัครเรียนใน ภาควิชาคอมพิวเตอรธุรกิจมีมากกวา หารอย เราจะมีการสอบคัดเลือก หรือ เชน ถาเงินเดือนเพิ่มขึ้นฉันจะ ซื้อบาน อะไรทํานองนี้ ซึ่งในดานของการเขียน code นั้น การตัดสินใจจะทําไดโปรแกรมก็ตอ  งมี ความสามารถทีจ ่ ะเปรียบเทียบไดกอน เชน เปรียบเทียบถึงความมากกวา นอยกวา หรือ เปรียบเทียบถึง ความเทากัน และความไมเทากัน ในบททีส ่ องเราไดพูดถึง relational operator เพียงเล็กนอยในเรื่องของการทํางานกับตัวแปรที่มช ี นิดเปน boolean และ operator ที่วานี้ก็คือ < <= > >= == และ != เราจะมาดูถึงการใช operator เหลานี้ใน ประโยคทีม ่ ีการเลือกประมวลผลตามผลลัพธของการเปรียบเทียบนั้น ๆ ประโยคที่ใช if if เปนคําสั่งที่เรานํามาใชในการเลือกวาเราจะประมวลผลอะไรตามผลลัพธทเี่ กิดขึ้น if มีรูปแบบดังนี้ คือ if(expression) statement; โดยมีขอกําหนดวา expression จะตองเปนประโยคที่เมื่อมีการประมวลผลแลวจะไดคาที่เปน boolean ซึ่ง เปนไปไดเพียงแค true หรือ false เทานั้น เชน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

59

if(numberOfStudents >= 500) entranceExam = true; หรือ if(number < 0) number *= 10; number++; ถาคาของ expression เปนจริง ประโยคทีต ่ ามหลัง if จะถูกประมวลผล แตถา เปนเท็จก็จะไมถูก ประมวลผล เชนตัวอยางที่เห็นดานบนนี้ ถาคาของ number < 0 เปนจริงประโยค number *= 10 ก็จะ ไดรับการประมวลผล ภาพที่ 3.1 แสดงถึงขั้นตอนของการประมวลผลดวยการใช if กับประโยคในรูปแบบ ทั่วไป และประโยคการเปรียบเทียบ number ที่ไดกลาวถึงกอนหนานี้ if(expression) statement; other_statement;

เปนจริง?

no

yes

number <0

no

yes

statement

number *= 10;

other_statement

number++;

ภาพที่ 3.1 การใชประโยค if

ในบางครั้งเราก็อาจเขียนประโยค if ใหเปนรูปแบบที่อยูใ นบรรทัดเดียวกัน เชน ถาเราเปลีย ่ นประโยค ตัวอยางกอนหนานี้ใหอยูใ นบรรทัดเดียวกันเราก็จะได if(number < 0) number *= 10; number++; ซึ่งถูกตองตามหลักไวยากรณของ Java แตโดยทั่วไปแลวการขึ้นบรรทัดใหมสําหรับประโยคทีต ่ ามมา หลังจากการเปรียบเทียบสิ้นสุดลง จะทําใหดู code ไดงายขึ้น ลองดูโปรแกรมตัวอยางการตรวจสอบวา ตัวเลขที่ user ใสเขาสูโปรแกรมเปนเลขคูหรือไม /* IfStatement.java - Using if statement to find out whether a number * is odd or even */ import java.io.*; import java.lang.Integer; class IfStatement { public static void main(String[] args) throws IOException {

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

60

int number; //set up buffer stream InputStreamReader isr = new InputStreamReader(System.in); BufferedReader buffer = new BufferedReader(isr); //get input string System.out.print("Enter a number (int): "); String input = buffer.readLine(); //convert string to int number = Integer.parseInt(input);

}

}

//check if number is even or not if(number % 2 == 0) System.out.println(number + " is an even number.");

โปรแกรม IfStatement.java บอก user ใหใสตัวเลขหนึ่งตัว ซึ่งโปรแกรมไดจัดเก็บไวในตัวแปรชื่อ number หลังจากนั้นก็ทําการตรวจสอบวาตัวเลขที่อานมาเปนเลขคูหรือไมดวยประโยค if(number % 2 == 0) System.out.println(number + " is an even number."); ซึ่งถานําสองไปหาร number แลวไมมีเศษ (หารลงตัว) แสดงวาตัวเลขที่วา นี้เปนเลขคู ซึง่ โปรแกรมก็จะ แสดงขอความไปยังหนาจอบอกผูใชวา ตัวเลขที่ใสเขามาเปนเลขคู ดังเชนผลลัพธของการ run นี้ Enter a number (int): 45 Enter a number (int): 20 20 is an even number. โปรแกรมของเรายังไมใชโปรแกรมทีส ่ มบรูณ ดังจะเห็นไดจากผลลัพธที่ได ถาเราใส 45 โปรแกรมก็จะไม แสดงอะไรเลย จะแสดงก็ตอเมือ ่ ตัวเลขที่ใสเปนเลขคูเทานั้น เราจะกลับมาดูวาเราตองทําอยางไร ถึงจะ สามารถที่จะแสดงขอความไปยังหนาจอโดยแบงแยกวาตัวเลขนั้นเปน เลขคูหรือเลขคี่ การใช if ในประโยคที่มม ี ากกวาหนึง ่ ประโยค (if – block) การเขียน code ที่มีมากกวาหนึ่งประโยคนั้น ทําไดดวยการใชเครื่องหมาย {} ลอมรอบประโยคเหลานั้น (compound statement) ดังตัวอยางที่เห็นนี้ if(expression) { statement 1; statement 2; statement 3; … statement n; } เชน if(number % 2 == 0) { System.out.println(number + " is an even number."); number++; System.out.println("But " + number + " is not!"); }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

61

ทีนี้เราจะกลับไปยังประเด็นที่เราพูดถึงกอนหนานี้ เกี่ยวกับเรื่องของการแสดงผลทั้งที่เปนจริง และไมเปน จริง ในการตรวจสอบดวยการใช if นั้นเราสามารถที่จะบังคับการประมวลผลใหเกิดขึ้นทั้งที่เปนจริง และ เปนเท็จ อยางใด อยางหนึ่งดวยการใช else ตามหลังประโยคที่ตาม if มาอีกทีหนึ่ง รูปแบบโครงสรางของประโยค if – else นี้มีดังนี้ if(expression) statement; else other_statement; another_statement; ภาพที่ 3.2 แสดงถึงโครงสรางของ if – else

yes

เปนจริง?

statement

no

other_statement

another_statement

ภาพที่ 3.2 การใช if - else

จากโปรแกรม IfStatement.java ถาเราตองการทีจ ่ ะแสดงผลถาตัวเลขที่ user ใสเขาสูโปรแกรมเปนเลข คี่ เราก็ตองเปลีย ่ น code ของเราใหเปนดังนี้ /* IfElse.java - Using if - else statement to find out whether a * number is odd or even */ import java.io.*; import java.lang.Integer; class IfElse { public static void main(String[] args) throws IOException { int number; //set up buffer stream InputStreamReader isr = new InputStreamReader(System.in); BufferedReader buffer = new BufferedReader(isr); //get input string System.out.print("Enter a number (int): "); String input = buffer.readLine();

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

62

//convert string to int number = Integer.parseInt(input); //check if number is even or not if(number % 2 == 0) System.out.println(number + " is an even number."); else System.out.println(number + " is an odd number.");

}

}

System.out.println("Good Bye.");

ประโยคที่เราไดเขียนเพิ่มเขาสูโปรแกรมของเรา คือ else System.out.println(number + " is an odd number."); System.out.println("Good Bye."); ซึ่งจะทําใหโปรแกรมของเราทําการประมวลผลประโยคที่อยูถ  ัดมาจาก else ถา number % 2 == 0 เปน เท็จ และตัวเลขที่จะทําใหประโยคนีถ ้ ูกประมวลผลก็คือ ตัวเลขที่เปนเลขคี่ (นํา 2 ไปหารแลวเหลือเศษ) ลองดูผลลัพธของการ run นี้ Enter a number (int): 45 45 is an odd number. Good Bye. Enter a number (int): 80 80 is an even number. Good Bye. จะเห็นวาการนําเอา if – else มาใชทําใหโปรแกรมของเราสนองตอบความตองการในการแสดงผล เมื่อ การตรวจสอบไดผลที่เปนจริงทางหนึ่ง และเมื่อผลของการตรวจสอบเปนเท็จ อีกทางหนึง่ เนื่องจาก if – else ก็เปน statement ตัวหนึง่ ดังนั้นเราก็สามารถที่จะนําเอา if – else ไปใสไวในประโยค ที่เปน if – else อีกประโยคหนึง่ ได หรือแมแตกระทั่งหลาย ๆ ประโยค เราเรียกประโยคที่ใช if – else แบบนี้วา Nested – if ซึ่งมีรูปแบบโครงสราง ที่มีลักษณะคลาย ๆ กับที่เห็นนี้ (อาจมีประโยค if – else มากกวา หรือนอยกวา) if(expression 1) { statement 1; statement 2; } else if(expression 2) statement 3; else { statement 4; statement 5; }

หรือ

if(expression 1) { statement 1; statement 2; } else if(expression 2) statement 3; else { statement 4; statement 5; }

จากโครงสรางตัวอยางดานบนนี้ประโยคทีจ ่ ะไดรับการประมวลผลถา expression 1 เปนจริงคือ statement 1 และ statement 2 สวน statement 3 จะไดรบ ั การประมวลผล ถา expression 2 เปนจริง และ statement 4 และ statement 5 จะไดรบ ั การประมวลผลก็ตอเมื่อ expression 1 และ expression 2 เปนเท็จ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

63

ลองมาดูโปรแกรมตัวอยางการใช Nested – if ในโปรแกรม Grades.java /* Grades.java - Using Nested - if finding letter grade * from a given score */ import java.io.*; import java.lang.Integer; class Grades { public static void main(String[] args) throws IOException { int score; char grade; //set up buffer stream InputStreamReader isr = new InputStreamReader(System.in); BufferedReader buffer = new BufferedReader(isr); //get input string System.out.print("Enter your score: "); String input = buffer.readLine(); //convert string to int score = Integer.parseInt(input); //determine grade by given score if(score >= 90) grade = 'A'; else if(score >= 80) grade = 'B'; else if(score >= 70) grade = 'C'; else if(score >= 60) grade = 'D'; else grade = 'F';

}

}

System.out.println("Your grade is " + grade);

โปรแกรม Grades.java ใชเกณฑการใหเกรดคือ ถา score มีคา มากกวาหรือเทากับ มากกวาหรือเทากับ มากกวาหรือเทากับ มากกวาหรือเทากับ ต่ํากวา 60 ได F

90 80 70 60

ได ได ได ได

A B (อยูระหวาง 80 ถึง 89) C (อยูระหวาง 70 ถึง 79) D (อยูระหวาง 60 ถึง 69)

เราไดออกแบบใหการตรวจสอบเปนไปไดทุกกรณีดวยการใชการเปรียบเทียบจาก 90 ลงไปถึง 60 ตาม ขั้นตอน คือ ถา user ใส score ที่มค ี าเทากับ 75 การเปรียบใน if แรก และ if ที่สองจะเปนเท็จ แตจะมา เปนจริงใน if ที่สามคือ score >= 70 ประโยคทีต ่ ามมา grade = 'C' ก็จะไดรับการประมวลผล สวนใน กรณีสุดทายนั้น ประโยค grade = 'F' จะไดรบ ั การประมวลผลก็ตอเมื่อ ทุก ๆ กรณีของการตรวจสอบกอน หนานี้เปนเท็จทั้งหมด ผูอานควรตรวจสอบประโยค if – else จากตัวอยางดวยคา score ที่แตกตางกัน เพื่อใหเกิดความเขาใจมากยิ่งขึ้น ผลลัพธของการ run ดวยขอมูลบางสวน

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

64

Enter your score: 87 Your grade is B Enter your score: 45 Your grade is F Enter your score: 92 Your grade is A เราสามารถทีจ ่ ะเขียนโปรแกรม Grades.java ขึ้นใหมดวยการใช operator && หรือ || ชวยในการ ตรวจสอบถึงสถานะภาพของ score วาอยูในกลุมใด ลองมาดูกัน /* Grades2.java - Using Nested - if finding letter grade * from a given score */ import java.io.*; import java.lang.Integer; class Grades2 { public static void main(String[] args) throws IOException { int score; char grade; //set up buffer stream InputStreamReader isr = new InputStreamReader(System.in); BufferedReader buffer = new BufferedReader(isr); //get input string System.out.print("Enter your score: "); String input = buffer.readLine(); //convert string to int score = Integer.parseInt(input); //determine grade by given score if(score >= 90) grade = 'A'; else if(score >= 80 && score <= 89) grade = 'B'; else if(score >= 70 && score <= 79) grade = 'C'; else if(score >= 60 && score <= 69) grade = 'D'; else grade = 'F';

}

}

System.out.println("Your grade is " + grade);

เราเปลี่ยน code ในการตรวจสอบใหมใหเปน if(score >= 90) grade = 'A'; else if(score >= 80 && score <= 89) grade = 'B'; else if(score >= 70 && score <= 79)

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

65

grade = 'C'; else if(score >= 60 && score <= 69) grade = 'D'; else grade = 'F'; ซึ่งเมื่อไดลอง run ดูแลวก็ไดผลลัพธเหมือนกันกับที่ไดจากโปรแกรม Grades.java แตขน ั้ ตอนของการ ตรวจสอบไมเหมือนกัน เราไดพูดกอนหนานี้วา ถามีการใช && และคาของประโยคที่อยูทางดานหนาของ && มีคาเปนจริง ประโยคที่อยูท  างดานหลังก็จะไดรับการประมวลผลดวย เชน สมมติวา score มีคาเปน 85 การประมวลผลใน if แรกจะเปนเท็จ Java ก็จะประมวลผล if ที่สอง คือ else if(score >= 80 && score <= 89) ซึ่งที่นี่เองที่ Java จะประมวลผลประโยคที่อยูหลัง && ดวยเพราะประโยคที่อยูท  างดาน หนา คือ score >= 80 นั้นเปนจริง กรณีอื่น ๆ ที่มีลักษณะคลายกันก็จะถูกประมวลผลในแบบเดียวกันนี้ ซึ่งเปนการประมวลผลทีซ ่ ้ําซอน ทั้ง ๆ ที่ไมมค ี วามจําเปนที่ตอ  งทําเลย แตนเี่ ปนเพียงตัวอยางเดียวเทานั้น มีกรณีอีกหลายกรณีที่ ตองใช && หรือ || เขามาชวยในการตรวจสอบจริง ๆ เชนในกรณีของโปรแกรม ตอไปนี้ ซึ่งเปนโปรแกรมตรวจสอบวา ตัวอักษรที่กําหนดใหอยูในกลุมนั้น ๆ หรือไม /* UpperLower.java - Using && in if - else statement */ import java.io.*; class UpperLower { public static void main(String[] args) throws IOException { char ch = 'F';

}

}

if(ch >= 'A' && ch <= 'Z') System.out.println(ch + " is an uppercase letter."); else if(ch >= 'a' && ch <= 'z') System.out.println(ch + " is a lowercase letter.");

โปรแกรมกําหนดใหตัวแปร ch มีคาเปนอักษร F ตัวใหญ และใชประโยค if – else ทําการตรวจสอบวา ตัวอักษรทีว่ านี้เปนอักษรตัวใหญหรือตัวเล็ก ซึ่งก็แนนอนวาผลลัพธที่ไดจะตองเปนตัวใหญ แตเราตองการ ที่จะแสดงใหเห็นถึงการใช && เขามาชวยในการตรวจสอบคาของ ch ที่เราไดกําหนดขึ้น ในการเปรียบเทียบนั้น Java จะใชคา ASCII (Unicode) ในการเปรียบเทียบตัวอักษรทั้งสองตัว โดยใน ตอนแรกจะเปรียบเทียบ F กับ A (70 กับ 65) ซึ่งผลของการเปรียบเทียบเปนจริง จึงตองเปรียบเทียบ F กับ Z (70 กับ 90) ซึ่งก็เปนจริง ดังนั้นประโยคทีต ่ ามมา System.out.println(ch + " is an uppercase letter."); จึงไดรับการประมวลผล เชนเดียวกันกับตัวอักษรตัวเล็ก ถา ch เก็บอักษรที่เปนตัวเล็กอยูการ เปรียบเทียบจะเกิดขึ้นในประโยค else – if ที่ตามมา โปรแกรมตอไปนี้แสดงการใช || ในการตรวจสอบวาเดือนทีก ่ ําหนดใหอยูในฤดูอะไร /* Season.java - Using || in if - else statement */ import java.io.*; import java.lang.Integer; class Season { public static void main(String[] args) throws IOException { int month; String season, input; InputStreamReader in; BufferedReader buffer; System.out.print("Enter month (1 – 12): "); in = new InputStreamReader(System.in);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

66

buffer = new BufferedReader(in); input = buffer.readLine(); month = Integer.parseInt(input); if(month == 3 || month == 4 || month == 5 || month == 6) season = "Summer"; else if(month == 7 || month == 8 || month == 9 || month == 10) season = "Rainy"; else if(month == 11 || month == 12 || month == 1 || month == 2) season = "Winter"; else season = "Never heard of it!";

}

}

System.out.println(month + " is in " + season);

โปรแกรม Season.java ใช || ในการตรวจสอบวา month ที่ user ใสเขาสูโปรแกรมนั้นอยูในฤดูอะไร โดยเรากําหนดใหเดือน 3 – 6 เปนฤดูรอน 7 – 10 เปนฤดูฝน และ 11 – 2 เปนฤดูหนาว (ซึ่งเดียวนีช ้ ักจะ ไมแนนอนเสียแลว) ลองมาดูผลลัพธจากการ run ดีกวา Enter month (1 – 12): 4 4 is in Summer Enter month (1 – 12): 8 8 is in Rainy Enter month (1 – 12): 1 1 is in Winter Enter month (1 – 12): 20 20 is in Never heard of it! Operator || นั้นเปนการเปรียบเทียบขอมูลทีอ ่ าจเปนไดหลาย ๆ อยาง ดังทีเ่ ห็นในโปรแกรม ถาเราใหคา ของ month เปน 3 4 5 หรือ 6 เราก็กําหนดให season มีคาเปน Summer สวนเดือนอื่น ๆ ก็เชนเดียวกัน ในทางตรงกันขามถาเราใช && แทนโปรแกรมของเราก็จะไมทํางานตามที่เราคาดหวังไว กลาวคือ คาของ month ไมสามารถเปนไปไดทงั้ สี่คา โปรแกรมก็จะประมวลผลประโยคที่ตาม else ตัวสุดทายตลอดไป ผูอานควรตรวจสอบวาที่กลาวมานี้ เปนจริงหรือไม ในการใช Nested if – else นั้นเราจะตองระวังวาทุก ๆ if ที่เราใชจะตองมี else หรือไมเพราะ Java จะ ตรวจสอบวา else ที่ใชนั้นวามี if อยูกอนหนาหรือไม สมมติวา มีเราก็ตองระวังในเรื่องของขั้นตอนการ ตรวจสอบ วาเปนไปอยางที่เราตั้งใจหรือไม เชนตัวอยางนี้ /* DanglingElse.java */ import java.io.*; class DanglingElse { public static void main(String[] args) { int x = 7, y = 99; if(x > 5) if(y > 5) System.out.println("x and y is greater than 5"); else System.out.println("x is less than 5");

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

}

การประมวลผลแบบวน (Repetition)

67

}

โปรแกรม DanglingElse.java ที่เห็นนี้เมื่อ run แลวผลลัพธที่ไดคือ x and y is greater than 5 ซึ่งเปนไปตามที่เราคิดไว แตถาเราเปลีย ่ นคาของ y ใหเปน 2 ผลลัพธที่ไดกลับเปน x is less than 5 ซึ่งไมใชสิ่งที่เราตองการ เพราะเรารูวา x มีคามากกวา 5 สิ่งที่เกิดขึ้นคือ Java จัดให else นั้นคูกับ if ตัวที่ สอง ดังนี้ if(x > 5) if(y > 5) System.out.println("x and y is greater than 5"); else System.out.println("x is less than 5"); เพราะฉะนั้นถาเราตองการใหการประมวลผลเปนไปตามที่เราตองการ เราตองใช {} เปนตัวชวย ดังนี้ if(x > 5) { if(y > 5) System.out.println("x and y is greater than 5"): } else System.out.println("x is greater than 5"); ซึ่งเมื่อ run ดูแลวก็จะไดผลลัพธเปนไปตามที่เราตองการ คือ ไมมีผลลัพธใด ๆ แสดงไปยังหนาจอถา y มีนอยกวา หรือเทากับ 0 ถึงเวลาที่เราจะกลับไปปรับปรุงโปรแกรม Quadratic.java ที่เราไดพด ู ถึงในบททีส ่ อง เพือ ่ ใหมีการ ตรวจสอบคาของ determinant ที่อาจเปน 0 ดวยการใช if ในประโยค //calculate determinant double d = b * b – 4 * a * c; if(d <= 0) { System.err.println("Error: cannot find square root"); System.exit(1); } double det = Math.sqrt(d); เราไดกําหนดใหมีการตรวจสอบคาของ d กอนการเรียกใช Math.sqrt() ถาคาของ d นอยกวา หรือเทากับ 0 เราจะฟองไปยัง user พรอมกับยุติการทํางานของโปรแกรมทันที ดวยการเรียกใช System.exit(1) /* Quadratic.java - Calculating roots of function */ class Quadratic { public static void main(String[] args) { double a, b, c; //4x2 + 20x + 16 = 0 a = 4; b = 20; c = 16; //calculate determimant double d = b * b – 4 * a * c;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

68

if(d <= 0) { System.err.println("Error: cannot find square root"); System.exit(1); } double det = Math.sqrt(d); //calculate roots double x1 = (-b + det) / (2 * a); double x2 = (-b - det) / (2 * a);

}

}

System.out.println("Root 1 = " + x1); System.out.println("Root 2 = " + x2);

การใช Conditional Operator (? :) Java มี operator อีกตัวหนึ่งทีเ่ ราสามารถนํามาใชแทน if – else ได เราเรียก operator ตัวนี้วา Conditional operator หรือ operator ที่มี expression (statement) อยูสามตัว ซึ่งมีโครงสรางดังนี้ คือ (expression) ? (true statement) : (false statement); เชน (number % 2 == 0) ? System.out.println("Even number.") : System.out.println("Odd number."); ลองดูโปรแกรมตัวอยางกัน /* OddEven.java */ import java.io.*; class OddEven { public static void main(String[] args) { int num; String result;

}

}

num = (int)(Math.random() * 100; result = (num % 2 == 0) ? "Even" : "Odd"; System.out.println(num + " is an " + result + " number.");

โปรแกรม OddEven.java ใช operator ? : ในการตรวจสอบวา num เปนเลขคูหรือ เลขคี่ ซึ่งถาเปน อยางใดอยางหนึ่งก็จะเก็บขอมูลนั้น (Even หรือ Odd) ไวในตัวแปร result แลวจึงแสดงผลไปยังหนาจอ หลังจากนั้น ดังนี้ 65 is an Odd number. โปรแกรม Min.java ที่เห็นดานลางนี้ใช operator ? : ในการหาคาตัวเลขทีน ่ อยทีส ่ ุดระหวางเลขสองตัวที่ กําหนดให /* Min.java */ import java.io.*; class Min {

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

69

public static void main(String[] args) { int num1 = 45, num2 = 89;

}

}

int min = (num1 < num2) ? num1 : num2; System.out.println("Min number is " + min);

ผลลัพธที่ไดจากการ run คือ Min number is 45 การใช operator ? : ก็คือการใช if – else นั่นเองดังนั้นก็เปนเรื่องของผูเขียนโปรแกรมเองวาอยากทีจ ่ ะใช operator ตัวไหน เพราะทั้งสองใหผลการประมวลผลในลักษณะเดียวกัน การใช switch Java มีคําสั่งอีกตัวหนึ่งที่เราสามารถนํามาใชแทน if – else ได คําสั่งนี้ก็คือ switch ซึ่งมีโครงสรางดังนี้ switch(expression) { case value1 : statement; break; case value2 : statement; break; …

}

default : statement; break;

คาที่ไดจาก expression ของ switch นั้นจะตองเปนคาที่มช ี นิดเปน char byte short หรือ int เทานั้น ถา เปนคาชนิดอื่น Java จะฟองดวย error ทันที ภาพที่ 3.3 แสดงถึงขั้นตอนการทํางานของ switch

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

yes เปนจริง?

70

statement

break

statement

break

no

เปนจริง?

yes

no default

break

ทําคําสั่งอื่น ๆ ในโปรแกรม

ภาพที่ 3.3 ขั้นตอนการทํางานของ switch

คําสั่ง break ใน switch นั้นสําคัญมาก ๆ ถาเราไมใส การทํางานของ switch ก็จะไมไดผลลัพธดังที่เรา ไดคาดการณไว เราลองมาดูตวั อยางโปรแกรมการใช switch ดู /* Switch.java - Using switch * to differentiate input */ import java.io.*; import java.lang.Integer; class Switch { public static void main(String[] args) throws IOException { int month; String season, input; InputStreamReader in; BufferedReader buffer; System.out.print("Enter month (1 – 12): "); in = new InputStreamReader(System.in); buffer = new BufferedReader(in); input = buffer.readLine(); month = Integer.parseInt(input); switch(month) { case 3: case 4: case 5: case 6: season = "Summer"; break; case 7: case 8: case 9: case 10: season = "Rainy"; break; case 11: case 12: case 1: case 2: season = "Winter"; break; default : season = "Never heard of it!";

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

}

}

การประมวลผลแบบวน (Repetition)

71

break; } System.out.println(month + " is in " + season);

เราไดทําการเปลี่ยนแปลงโปรแกรม Season.java ที่ใช if – else ใหมาใช switch แทน โดยเราไดรวม เอาเดือนที่อยูในฤดูเดียวกันเหมือนที่เราทํากับโปรแกรม Season.java มาอยูในกลุมของ case เดียวกัน จะเห็นวาเราเขียน case ตาง ๆ ที่อยูในกลุมเดียวกันตามหลังกันไปโดยไมมีการประมวลผลใด ๆ จนกวาจะ จบ case สุดทายในกลุมนั้น เชน case 3: case 4: case 5: case 6: season = "Summer"; break; Java จะประมวลผล case 3 กอนแตเราไมมีประโยคใด ๆ ใน case นี้ดังนั้น Java จึงประมวลผล case 4 case 5 และจนกระทั่งมาถึง case 6 ซึ่งเปน case สุดทายในกลุม Java จึงประมวลผลประโยค season = "Summer" และ break การนําเอา case ตาง ๆ มาตอกันในลักษณะนี้มีผลเหมือนการประมวลผลดวยการใช operator || ใน ประโยคที่เรียกใช if ผูอานควรสังเกตถึงการใช switch ในลักษณะนี้ใหดี เพราะเปนวิธีการทีช ่ วยลด ขั้นตอนการเขียนไดดีพอสมควร ผลลัพธที่ไดจากการ run โปรแกรม Switch.java ก็เหมือนกันกับการ run โปรแกรม Season.java เรามาลองดูตัวอยางการใช switch อีกสักตัวหนึ่ง /* Switch2.java */ import java.io.*; import java.lang.Integer; class Switch2 { public static void main(String[] args) throws IOException { int digit; BufferedReader buffer; InputStreamReader isr; String input; System.out.print("Enter a digit: "); isr = new InputStreamReader(System.in); buffer = new BufferedReader(isr); input = buffer.readLine(); digit = Integer.parseInt(input); switch(digit) { case 1: System.out.println("You break; case 2: System.out.println("You break; case 3: System.out.println("You break; case 4: System.out.println("You break; case 5: System.out.println("You break; case 6: System.out.println("You

entered ONE."); entered TWO."); entered THREE."); entered FOUR."); entered FIVE."); entered SIX.");

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

}

}

}

การประมวลผลแบบวน (Repetition)

72

break; case 7: System.out.println("You entered SEVEN."); break; case 8: System.out.println("You entered EIGHT."); break; case 9: System.out.println("You entered NINE."); break; case 0: System.out.println("You entered ZERO."); break; default: System.out.println("Sorry - not a digit!"); break;

โปรแกรม Switch2.java บอก User ใหใสตัวเลขระหวาง 0 – 9 และจะแสดงตัวหนังสือแทนตัวเลข เหลานั้นกลับไปยังหนาจอ ซึ่งเมื่อ run แลวก็จะไดผลลัพธดงั นี้ Enter a digit: 9 You entered NINE. Enter a digit: 2 You entered TWO. Enter a digit: 36 Sorry - not a digit! เมื่อเราใส 36 โปรแกรมกลับบอกวาไมใชตัวเลข ทั้งนี้เพราะโปรแกรมของเราตรวจสอบเฉพาะตัวเลขเพียง ตัวเดียวเทานั้น เราตองปรับปรุงโปรแกรมของเราใหมถาเราตองการที่จะตรวจสอบตัวเลขจริง ๆ ทั้งหมด การทํางานแบบวน (Loop) หลาย ๆ ครั้งทีโ่ ปรแกรมเมอรตองการทีจ ่ ะใหโปรแกรมทําการประมวลผลในรูปแบบเดิมซ้ํา ๆ กัน เชน คูณ ตัวเลข 1 – 10 ดวย 2 หรือ อานขอมูลจาก keyboard จนกวา user จะพอใจ เราสามารถนําเอาชุดคําสั่งที่ Java มีใหมาใชกับการทํางานที่วานี้ไดอยางไมยากนัก ลองดูโปรแกรมทีท ่ ําการแสดงคาจาก 1 – 10 ไป ยังหนาจอนี้ /* ForLoop.java */ import java.io.*; class ForLoop { public static void main(String[] args) { int number = 1; System.out.println("Number number++; System.out.println("Number number++; System.out.println("Number number++; System.out.println("Number number++; System.out.println("Number number++; System.out.println("Number number++;

now is " + number); now is " + number); now is " + number); now is " + number); now is " + number); now is " + number);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

}

}

การประมวลผลแบบวน (Repetition)

System.out.println("Number number++; System.out.println("Number number++; System.out.println("Number number++; System.out.println("Number

73

now is " + number); now is " + number); now is " + number); now is " + number);

แนนอนผลลัพธที่ไดก็ตองเปน Number Number Number Number Number Number Number Number Number Number

now now now now now now now now now now

is is is is is is is is is is

1 2 3 4 5 6 7 8 9 10

การแสดงคาจาก 1 – 10 นั้นยังไมมีปญหาอะไรมากมายนัก ถาเราตองการที่จะแสดงคาจาก 1 – 100 หรือ จาก 1 – 1000 หละ เราคงตองพิมพจนมือเมื่อยแนเลย ลองมาดูวาเราจะใช loop ชวยในการทํางานใน ลักษณะนี้ไดอยางไร Java มีโครงสรางหลายตัวที่เราสามารถนํามาใชในการทํางานแบบวนได คําสั่งทีว่ านี้ คือ while, do..while และ for ชุดคําสั่งแรกที่เราจะดูกัน คือ for loop การใช for loop กอนที่เราจะไปดูโครงสรางของ for loop กันเรามาดูกันวาโปรแกรมกอนหนานี้ ถาใช for loop แลวจะมี หนาตาเปนอยางไร /* ForLoop2.java */ import java.io.*; class ForLoop2 { public static void main(String[] args) { int number;

}

}

for(number = 1; number <= 10; number++) System.out.println("Number now is " + number);

จะเห็นวาโปรแกรมของเราสั้นลงมาก คําสั่งใน for loop บอกให Java รูวาการประมวลผลตองทําทั้งหมด 10 ครั้งโดยเริ่มตนการประมวลผล เมื่อ number มีคาเทากับ 1 ไปจนกวา number จะมีคา เปน 10 ซึ่งเมื่อ number มีคาเปน 10 Java ก็จะยุติการประมวลผลทั้งหมด และผลลัพธที่ไดก็เหมือนกันกับโปรแกรม ForLoop.java ที่เราเขียนขึ้นมากอนหนานี้ โครงสรางของ for loop มีดังนีค ้ ือ for(expression1 ; expression2 ; expression3) statement;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

74

โดยที่ expression ทั้งสามตัวมีการทํางานทีต ่ างกัน expression1 จะถูกประมวลผลเปนตัวแรกสุด ซึ่ง โดยทั่วไป expression นี้มักจะถูกเรียกวา initialization expression คือทําหนาทีใ่ นการกําหนดคา เบื้องตนใหกับตัวแปรทีจ ่ ะนํามาใชใน for loop หลังจากนั้น expression2 ก็จะถูกประมวลผล ซึ่งถาการ ประมวลผลเปนจริงตามเงื่อนไข statement ที่อยูใน for loop ก็จะถูกประมวลผล และ for loop จะยุติการ ทํางานทันทีทก ี่ ารประมวลของ expression2 เปนเท็จ เมื่อ statement ที่อยูใน for loop สิ้นสุดการ ประมวลผลแลว expression3 ก็จะไดรับการประมวลผล และ for loop จะกลับไปประมวลผล expression2 อีกครั้ง ซึ่งถาเปนจริง statement ก็จะถูกประมวลผลอีกครั้ง ทําอยางนี้ไปจนกวา expression2 จะเปนเท็จ เราเรียก expression2 วา loop condition และ expression3 วา increment expression ภาพที่ 3.4 แสดงแผนผังการทํางานของ for loop

expression1

expression2 (จริง ?)

no

yes statement

expression3

statement อื่น ๆ ในโปรแกรม

ภาพที่ 3.4 ขั้นตอนการทํางานของ for loop

เรากลับมาดูโปรแกรม ForLoop2.java ที่เราเขียนกอนหนานีว้ ามีการทํางานอยางไร เราเริ่มตนดวยการ เขียน for loop for(number = 1; number <= 10; number++) System.out.println("Number now is " + number); สิ่งที่ Java ทํากอนก็คือ กําหนดคาตัวแปร number ใหเปนหนึ่ง หลังจากนัน ้ ก็ทําการตรวจสอบวาตัวแปร number มีคานอยกวา หรือเทากับสิบหรือไม ซึ่งก็เปนจริง ดังนั้น Java จึงประมวลผลประโยคที่อยูใน for loop เมื่อเสร็จแลวจึงไปประมวลผลประโยค number++ ซึ่งเปนการเพิ่มคาใหกับตัวแปร number เสร็จ แลวจึงกลับไปตรวจสอบวา number <= 10 อีกครั้ง ทําไปเรื่อย ๆ จนกวา number จะมีคา มากกวาสิบจึง จะยุติการทํางาน โดยสรุปแลวขั้นตอนของ for loop มีดังนี้คอ ื 1. กําหนดคาเบื้องตนใหกับ number 2. ตรวจสอบวา number <= 10 หรือไม ถาเปนจริง ประมวลผลประโยค System.out.println("Number now is " + number); ถาเปนเท็จ ยุตก ิ ารทํางานของ for loop 3. ประมวลผลประโยค number++ 4. กลับไปทําคําสัง่ ในขอสองใหม

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

75

Expression ที่สําคัญทีส ่ ด ุ ทีจ ่ ะทําให for loop ทํางานตอ หรือยุติการทํางานก็คือ expression ทีส ่ อง ดังนั้นในการใช for loop เราจึงตองระมัดระวังถึงประโยคที่ใชในการตรวจสอบวาสามารถทีจ ่ ะทําไดทั้ง สองกรณีหรือไม เพราะถาเราตรวจสอบไมดก ี ารทํางานของ for loop อาจทําไปโดยไมมก ี ารสิ้นสุด หรือที่ เรียกวา Infinite loop ตัวอยางเชน ถาเราเปลี่ยน for loop ของเราใหเปนดังนี้ for(number = 1; number > 0; number++) System.out.println("Number now is " + number); For loop ใหมของเราก็จะทํางานโดยไมมท ี ส ี่ ิ้นสุด เพราะวาคาของ number จะมากกวาศูนยอยู ตลอดเวลา ทําใหประโยคของการตรวจสอบเปนจริงเสมอ การเขียน for loop ใหทํางานตลอดเวลานั้นสามารถเขียนไดหลายแบบ ตัวอยางเชน int number = 1; for(;;) System.out.println("Number now is " + number); เราให for loop ทํางานไปเรื่อย ๆ ดวยการยกเลิก expression ทั้งสามตัวทีอ ่ ยูใน loop หรือยกเลิก expression ที่หนึ่งและสาม ดังนี้ int number = 1; for(;number > 0;) System.out.println("Number now is " + number); ถาเราตองการ infinite loop ทีไ ่ มมีประโยคใด ๆ เลยก็ทําได ดังนี้ for( ; ;) ; เราลองมาดูการใช for loop ในการบวกเลขจาก 1 ถึง 100 /* Add1To100.java */ import java.io.*; class Add1To100 { public static void main(String[] args) { int total = 0;

}

}

for(int i = 1; i <= 100; i++) total += i; System.out.println("Sum of 1 - 100 is " + total);

ผลลัพธของการ run คือ Sum of 1 – 100 is 5050 ตัวอยางโปรแกรมตอไปนี้ทาํ การคํานวณหาดอกเบี้ยทบตนในแตละป เปนจํานวนเทากับจํานวนปที่ user เปนผูกําหนดจากเงินฝากเริ่มตนทีห ่ นึ่งพันบาท (หรือเทากับจํานวนที่ user เปนผูใสเขาสูโ ปรแกรม) โดย ใชสูตรการในการคํานวณ คือ amount = p(1 + r)n โดยที่

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

76

p คือ จํานวนเงินเริ่มตน (principal) r คือ อัตราดอกเบี้ยประจําป n คือ จํานวนของปที่ตองการหา amount คือ เงินตนที่นําฝากของทุกป /* Interests.java */ import java.io.*; import java.lang.Integer; class Interests { public static void main(String[] args) throws IOException { double amount; //amount at the end of year double principal; //first deposit double rate; //annual interests rate int years; //number of years BufferedReader buffer; InputStreamReader isr; String input; //get input from user (principal, rate, years) System.out.print("Enter amount to deposit: "); isr = new InputStreamReader(System.in); buffer = new BufferedReader(isr); input = buffer.readLine(); principal = Double.parseDouble(input); System.out.print("Enter interests rate: "); input = buffer.readLine(); rate = Double.parseDouble(input); System.out.print("Enter number of year: "); input = buffer.readLine(); years = Integer.parseInt(input);

}

}

//calculate and display amount System.out.println("\nYear\tAmount on deposit"); for(int y = 1 y <= years; y++) { amount = principal * Math.pow(1.0 + rate, y); System.out.println(y + "\t" + amount); } System.out.print("\nTotal interests after " + years); System.out.println(" years is " + (amount - principal));

ผลลัพธของการ run ดวย principal = 10000 rate = 0.25 และ years = 5 Enter amount to deposit: 10000 Enter interests rate: .25 Enter number of year: 5 Year 1 2 3 4 5

Amount on deposit 12500.0 15625.0 19531.25 24414.0625 30517.578125

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

77

Total interests after 5 years is 20517.578125 สวนประกอบทีส ่ ําคัญคือ for loop ที่ทําหนาที่คํานวณหาจํานวนเงินที่ไดรับในแตละป (พรอมทั้งดอกเบี้ย) เราใช method Math.pow() ในการหาคาของดอกเบี้ยในแตละป ซึ่งเมื่อหาไดแลวเราก็แสดงผลลัพธไป ยังหนาจอทันที for loop ของเรายุติการประมวลผลเมื่อคาของตัวแปร y มีคามากกวาตัวแปร years หลังจากแสดงจํานวนของเงินในแตละปแลว เมื่อออกจาก for loop เราก็แสดงจํานวนของดอกเบี้ย ทั้งหมดที่ไดจากการฝากในชวงนั้น ถาหากเราไมตอ  งการใชสูตรในการคํานวณหาดอกเบี้ย เราก็สามารถทําไดดว ยการคํานวณหาดอกเบี้ยกอน แลวจึงนําเอาดอกเบี้ยที่หาไดไปบวกกับเงินตน หลังจากนั้นก็คํานวณหาดอกเบี้ยจากเงินตนใหมนี้ ทําการ คํานวณจนกวาจะครบตามจํานวนปที่ไดกําหนดไว ดังที่แสดงดวย code นี้ amount = principal; System.out.println("\nYear\tAmount on deposit"); for(int y = 1; y <= years; y++) { double interests = amount * rate; //calculate interests amount += interests; //calculate new principal System.out.println(y + "\t" + amount); } เราลองมาดูโปรแกรมตัวอยางอีกตัวหนึ่งทีใ่ ช for loop ในการควบคุมการทํางานของโปรแกรม พรอมทั้ง ยอมให user ใสขอมูลหลาย ๆ ตัวในบรรทัดเดียวกันได /* AddNumbers.java - reading numbers from input line * user must specify space between those numbers and * hit <enter> when done. */ import java.io.*; import java.text.DecimalFormat; class AddNumbers { public static void main(String[] args) throws IOException { double number, sum = 0; //a number read and sum of numbers int count = 0; //total numbers read BufferedReader buffer; //input buffer InputStreamReader isr; //input stream StreamTokenizer token; //token from input stream DecimalFormat f = new DecimalFormat("0.00"); System.out.print("Enter numbers (space between – enter when done): "); isr = new InputStreamReader(System.in); buffer = new BufferedReader(isr); //get tokens from input buffer token = new StreamTokenizer(buffer); //set priority to EOL so that we can break out of the loop token.eolIsSignificant(true); //get each number from tokens //calculate the sum until EOL is reached for(; token.nextToken() != token.TT_EOL ;) { switch(token.ttype) { //token is a number case StreamTokenizer.TT_NUMBER: number = token.nval; //save token in number count++; //number of tokens read

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

78

sum += number; //calculate sum break; default: System.out.println("Token is not a number! " + token.toString()); break;

}

}

} } //calculate average and display result double average = sum / count; System.out.println("Sum of numbers = " + sum); System.out.println("Average of numbers = " + f.format(average));

โปรแกรม AddNumbers.java ใช method จาก class StreamTokenizer และ for loop เปนตัวชวยใน การดึงเอาขอมูลแตละตัวที่ User ใสเขาสูโปรแกรม เรากําหนดให user กดปุม <enter> เมื่อสิ้นสุดการใส ขอมูล ดังนั้นเราจึงจําเปนทีจ ่ ะตองบอกให Java รูวาปุม <enter> มีความสําคัญในการยุติการทํางานของ loop ซึ่งเราทําไดดวยการเรียกใช method eolIsSignificant() ดวยคาที่เปนจริงดังนี้ eolIsSignificant(true); ถาเราไมเรียก method นี้มาใชการกดปุม <enter> ของ user ก็จะไมมีผลใด ๆ ตอโปรแกรม (โปรแกรม จะไมยต ุ ิการทํางาน และเราตองกดปุม <ctrl> + c เพื่อใหโปรแกรมหยุดการทํางาน) เมื่อเรากําหนด ความสําคัญของปุม <enter> แลวเราก็เริ่มอาน token แตละตัวที่เราไดดึงมาจาก keyboard จนกวา token นั้นจะมีคาเปน EOL (End Of Line) ซึง่ เปนตัวกําหนดการสิ้นสุดของขอมูลในบรรทัดนั้น เราอาน token ที่มีอยูท  ั้งหมดใน buffer มาเก็บไวในตัวแปร token ดวยคําสัง่ token = new StreamTokenizer(buffer); หลังจากนั้นเราก็ตรวจสอบดูวา token ที่อยูถด ั ไปใน buffer เปน EOL หรือไม ซึ่งถาไมเปนเราก็เรียกใช switch เพื่อตรวจสอบดูวา token ที่อานมานัน ้ เปนตัวเลขหรือไม ถาเปนเราก็จะทําการบวกตัวเลขนี้เขากับ ตัวแปร sum พรอมกับเพิ่มคาใหกับตัวแปร count for(; token.nextToken() != token.TT_EOL ;) { switch(token.ttype) { //token is a number case StreamTokenizer.TT_NUMBER: number = token.nval; //save token in number count++; //number of tokens read sum += number; //calculate sum break; default: System.out.println("Token is not a number! " + token.toString()); break; } } เราตรวจสอบความเปนตัวเลขของ token ไดดวยการเปรียบเทียบ token.ttype กับ StreamTokenizer.TT_NUMBER และถาเปนจริง token ที่เปนตัวเลขจะถูกเก็บไวในตัวแปร nval (และมี ชนิดเปน double) ดังนั้นตัวแปร number จึงตองประกาศใหเปน double และการดึงคามาเก็บในตัวแปร number ทําไดดวยการกําหนดคาจากประโยค number = token.nval;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

79

เนื่องจากวาเราสนใจเฉพาะ token ที่เปนตัวเลขเทานั้นเราจึงไมสนใจ token ที่เปนชนิดอืน ่ ดังนั้นเราจึง เพียงแตสงคาของ token กลับคืนไปยังหนาจอถา token นั้นเปนชนิดอื่นที่ไมใชตวั เลข for loop ของเราจะทํางานไปเรื่อย ๆ จนกวา user จะกดปุม <enter> ซึ่งการกดปุม <enter> นี้จะทําให expression ที่มีอยูเพียงตัวเดียวใน for loop เปนเท็จ การทํางานของ for loop จึงสิ้นสุดลง ผูอานจะ สังเกตไดวาเราไมสนใจกับ expression ที่ 1 และ expression ที่ 3 ของ for loop เลยทั้งนีก ้ ็เพราะวาเรา ไมตองมีการกําหนดคาเบื้องตน หรือเพิ่มคาใด ๆ เลย การยุติการทํางานของ for loop เกิดจากการกดปุม <enter> ของ user เทานั้น ผลลัพธของการ run ดวยคาสมมติตาง ๆ Enter numbers (space between - enter when done): 20 30 45 789 12 34 Sum of numbers = 930.0 Average of numbers = 155.0 Enter numbers (space between - enter when done): 45 68 95 Sum of numbers = 208.0 Average of numbers = 69.33 Class StreamTokenizer ยังมี field อื่น ๆ ที่เราสามารถเรียกใชได แตไมไดกลาวไวในทีน ่ ี้เพราะวา โปรแกรม AddNumbers.java ของเราสนใจแตเฉพาะการอานตัวเลขเทานั้น ผูอานสามารถหาขอมูลได จาก javadoc ของ Sun เอง ในการใช for loop นั้นเราสามารถที่จะใช , (comma) เปนตัวแบงการประมวลในแตละ expression ได ดังตัวอยางโปรแกรมการหาผลรวมและคาเฉลีย ่ นของเลขจากหนึ่งถึงสิบนี้ /* Sum.java */ import java.io.*; class Sum { public static void main(String[] args) { int i, sum; for(i = 1, sum = 0; i <= 10; sum += i, i++) ;

}

}

System.out.println("Sum = " + sum); System.out.println("Average = " + (double)sum / (i-1));

เรากําหนดให expression1 ของเรามีขอความอยูสองขอความคือ i = 0 และ sum = 0 โดยเราใช , เปน ตัวแบงขอความทั้งสอง เชนเดียวกันกับ expression3 เรากําหนดใหมีขอความ sum += i และ i++ อยู และในตัว for loop นั้นเราไมมีการกําหนดประโยคใด ๆ เลย ทั้งนี้ก็เพราะวาเราไดกําหนดใหการหาผลรวม นั้นอยูใน expression3 แลว แตเราจะตองใส ; (หรือเราอาจใส {})เพื่อให Java รูวาเราไดจบ for loop ของเราแลว for(i = 1, sum = 0; i <= 10; sum += i, i++) ; หรือ for(i = 1, sum = 0; i <= 10; sum += i, i++) { } การทํางานของ for loop ที่วานี้ก็เหมือนกันกับการเขียน for loop แบบเดิม ตางกันตรงที่เราไดยาย ตําแหนงของประโยคสองประโยค เทานั้นเอง

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

80

sum = 0; for(i = 1; i <= 10; i++) sum += i; ตําแหนงของขอความการหาผลรวมก็มค ี วามสําคัญ เราตองกําหนดใหประโยค sum += i นั้นอยูกอน ประโยค i++ ทั้งนี้ก็เพราะวา Java จะประมวลผลประโยคทีอ ่ ยูทางซายของเครื่องหมาย , กอน แลวจึงจะ ประมวลผลประโยคที่อยูถด ั ไปทางขวา ซึ่งถาเรากําหนดให i++ อยูกอน sum += i การประมวลผลของ เราก็จะผิดพลาด คาของผลรวมที่ไดคลาดเคลื่อน สวนที่สําคัญอีกสวนหนึ่งก็คือ คาของ i สําหรับการคํานวณหาคาเฉลี่ย เราตองหักคาของ i ออกหนึ่งคา กอนนําไปหาร sum ก็เนื่องจากวาในขณะที่ for loop ยุติการทํางานนั้นคาของ i มีคาเปน 11 การหาผลรวมของ for loop ที่กลาวมาแลวนัน ้ เราสามารถทีจ ่ ะเขียนไดอีกหลายรูปแบบ เชน i = ; sum = 0; for( ; i <= 10; i++) ; sum += i; หรือ i = 1; sum = 0; for( ; i <= 10; ) { sum += i; i++; } หรือ sum = 0; for( i = 1; i <= 10; ) { sum += i; i++; } ผูอานควรคํานึงถึงการเขียน code ที่ดแ ู ลวอานไดงาย มีโครงสรางที่มองดูเปนสากล ดังนั้นถึงแมวา Java จะยอมใหเราเขียน code ไดอยางอิสระและหลายรูปแบบ เราก็ไมควรเขียน code ที่ยากตอการทําความ เขาใจ ยกเวนวาการเขียน code นั้น ๆ มีความจําเปนที่ตองใชรูปแบบนั้น ๆ ในการเขียน (จําเปนจริงหรือ?) การใช while loop การใช while loop ก็คลาย ๆ กับการใช for loop ตางกันเฉพาะโครงสรางบางโครงสรางเทานั้นเอง (ตําแหนงของ expression) เรามาดูโครงสรางของ while loop กัน while(expression) statement; while loop จะตรวจสอบวาคาของ expression นั้นเปนจริงหรือเท็จ ถาเปนจริงก็จะประมวลผลประโยค ตาง ๆ ที่อยูภ  ายใน while loop และจะประมวลผลประโยคอืน ่ ๆ ที่ตามมา (ภายนอก while loop) หลังจากที่หลุดออกจาก while loop แลว ภาพที่ 3.5 แสดงขั้นตอนการทํางานของ while loop

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

Expression (จริง ?)

81

no

yes

statement

Next statement

ภาพที่ 3.5 ขั้นตอนการทํางานของ while loop

เรามาลองใช while loop แทน for loop ที่เราไดใชในโปรแกรมตัวอยางบางตัวกอนหนานี้ /* Sum.java */ import java.io.*; class Sum { public static void main(String[] args) { int i, sum; i = 0; sum = 0; while(i <= 10) { sum += i; i++; }

}

}

System.out.println("Sum = " + sum); System.out.println("Average = " + (double)sum / (i-1));

สิ่งแรกที่เราตองทําก็คือการกําหนดคาเบื้องตนใหกับตัวแปร i และ sum หลังจากนั้นเราก็ทาํ การตรวจสอบ ดูวาประโยค i <= 10 เปนจริงหรือไม ซึ่งถาเปนจริงเราก็ให while loop ของเราทําการบวกคาของ i เขา กับตัวแปร sum พรอมทั้งเพิ่มคาใหกับ i เมื่อเสร็จแลว ถาเราลองเปรียบเทียบการใช while loop กับ for loop เราจะเห็นวา ประโยค i = 0; sum = 0; คือ expression ที่หนึ่งของ for loop และประโยค

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

82

i <= 10 ก็คือ expression ที่สองใน for loop สวนประโยค i++ ก็คือ expression ที่สามใน for loop นั่นเอง (ถึงแมวา เราไดกําหนดคาของ i ใหเริ่มตนที่ 0 ก็ไมทําใหการประมวลผลเปลี่ยนไป เพียงแตวา loop ของเราทํางานมากขึ้นอีกหนึ่งครั้ง เทานั้น) ทีนี้เรามาลองใช while loop แทน for loop ในโปรแกรม AddNumbers.java กัน /* AddNumbers2.java - reading numbers from input line user must specify space between those numbers and hit <enter> when done. (using while loop) */ import java.io.*; import java.text.DecimalFormat; class AddNumbers2 { public static void main(String[] args) throws IOException { double number, sum = 0; //a number read and sum of numbers int count = 0; //total numbers read BufferedReader buffer; //input buffer InputStreamReader isr; //input stream StreamTokenizer token; //token from input stream DecimalFormat f = new DecimalFormat("0.00");

}

}

System.out.print("Enter numbers (space between – enter when done): "); isr = new InputStreamReader(System.in); buffer = new BufferedReader(isr); //get tokens from input buffer token = new StreamTokenizer(buffer); //set priority to EOL so that we can break out of the loop token.eolIsSignificant(true); //get each number from tokens //calculate the sum until EOL is reached while(token.nextToken() != token.TT_EOL) { switch(token.ttype) { //token is a number case StreamTokenizer.TT_NUMBER: number = token.nval; //save token in number count++; //number of tokens read sum += number; //calculate sum break; default: System.out.println("Token is not a number! " + token.toString()); break; } } //calculate average and display result double average = sum / count; System.out.println("Sum of numbers = " + sum); System.out.println("Average of numbers = " + f.format(average));

เราแทบที่จะไมตองเปลี่ยนอะไรเลย เพียงแตเปลี่ยนประโยค for(; token.nextToken() != token.TT_EOL ;)

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

83

ใหเปน while(token.nextToken() != token.TT_EOL) เทานั้นเอง สวน code อื่น ๆ ก็ยังคงเหมือนเดิม ทั้ง for loop และ while loop เปนโครงสรางของการทํางานแบบวนทีต ่ องมีการตรวจสอบกอนวาประโยค ในการควบคุมของ loop ทั้งสองเปนจริงหรือเท็จ ซึ่งหมายถึงวาการทํางานของ loop ทั้งสองอาจไม เกิดขึ้นเลยถาการประมวลผลประโยคควบคุมเปนเท็จ แตถาเราตองการที่จะประมวลผลกอนอยางนอยหนึง่ ครั้ง เราจะทําอยางไร การใช do..while Java มีโครงสรางการใช loop อีกตัวหนึ่งทีย ่ อมใหมีการทํางานอยางนอยกอนหนึ่งครั้ง แลวจึงจะทําการ ประมวลผลประโยคควบคุม นัน ่ ก็คือ do … while ซึ่งมีโครงสรางดังนี้ do {

statement } while(expression); ภาพที่ 3.6 แสดงขั้นตอนการทํางานของ do … while loop

statement

yes

Expression (จริง ?)

no

statement

ภาพที่ 3.6 ขั้นตอนการทํางานของ do … while

ถาเราตองการที่จะทํางานอยางนอยหนึ่งครั้งกอนที่จะมีการตรวจสอบเพื่อยุติการทํางาน หรือทํางานตอไป do … while loop จะเปนโครงสรางที่เหมาะสมทีส ่ ุด โปรแกรมตัวอยางตอไปนี้แสดงถึงการใช do … while loop ในการตรวจสอบนั้น ๆ /* DoWhile.java - do .. while to repeat the program until user enter a letter other than 'y' */ import java.io.*;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

84

import java.lang.Integer; class DoWhile { public static void main(String[] args) throws IOException { int score; char grade, ch; //set up buffer stream InputStreamReader isr = new InputStreamReader(System.in); BufferedReader buffer = new BufferedReader(isr); do { //get input string System.out.print("Enter your score: "); String input = buffer.readLine(); //convert string to int score = Integer.parseInt(input); //determine grade by given score if(score > 90) grade = 'A'; else if(score > 80) grade = 'B'; else if(score > 70) grade = 'C'; else if(score > 60) grade = 'D'; else grade = 'F'; System.out.println("Your grade is " + grade); System.out.print("\nDO you want to continue? <y/n> : "); String response = buffer.readLine(); ch = (char)response.charAt(0);

}

}

} while(ch == 'y');

เราเพียงแตดัดแปลงโปรแกรมการหาเกรดของเรา ดวยการเพิ่ม do … while และประโยค System.out.print("\nDO you want to continue? <y/n> : "); String response = buffer.readLine(); ch = (char)response.charAt(0); ที่ใชสําหรับการถาม user วาตองการทํางานตอหรือไม โดยเราทําการดึงเอาตัวอักษรตัวแรกที่อยูใน บรรทัดนั้นออกมา ทําการเปรียบเทียบกับตัวอักษร y ใน expression ของ do … while loop ซึ่งถาการ เปรียบเทียบนั้นเปนจริงเราก็จะทํางานไปเรื่อย ๆ วิธีการเดียวที่จะทําให do … while loop ยุติการทํางานก็ คือ การใสตัวอักษร n (หรือ อืน ่ ๆ ที่ไมใช y) เราใช method chatAt() ดวยคา parameter ที่เปนศูนยเพื่อดึงเอาอักษรตัวแรกสุดใน buffer มาเก็บไว ในตัวแปร ch สําหรับการเปรียบเทียบประโยคควบคุมของ do … while loop ผลลัพธการ run โปรแกรมดวยคาตาง ๆ Enter your score: 89 Your grade is B

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

85

DO you want to continue? <y/n> : y Enter your score: 12 Your grade is F DO you want to continue? <y/n> : y Enter your score: 75 Your grade is C DO you want to continue? <y/n> : n เรามาลองดูโปรแกรมตัวอยางอีกตัวหนึ่งทีใ่ ช do … while loop ในการหาผลรวมของเลขระหวาง 1 – 100 /* Sum2.java */ import java.io.*; class Sum2 { public static void main(String[] args) { int i, sum; i = 0; sum = 0; do { sum += i; i++; } while(i <= 100);

}

}

System.out.println("Sum = " + sum); System.out.println("Average = " + (double)sum / (i-1));

ซึ่งเมื่อ run ดูก็ไดผลลัพธดังนี้ Sum = 5050 Average = 50.5 เราไมไดเปลี่ยนแปลงอะไรมากมายใน loop ของเราเพียงแตเปลี่ยนมาใช do … while loop เทานั้นเอง เพื่อใหเกิดความเขาใจในการทํางานของ loop ดียิ่งขึ้น เราจึงนําเอาตัวอยางของ code ที่ใช loop ใน รูปแบบตาง ๆ มาใหดูกัน ผูอานควรตรวจสอบถึงผลลัพธทค ี่ วรจะไดจากการทํางานของ loop เหลานี้ดวย มือ กอนที่จะเขียนโปรแกรมตรวจสอบ ตัวอยางที่ 1 class Loops { public static void main(String[] args) { int index = 1; while(index != 9) { index += 2; System.out.println(index); index--; }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

}

การประมวลผลแบบวน (Repetition)

86

}

ตัวอยางที่ 2 class Loops1 { public static void main(String[] args) { int index1, index2; index1 = 33; index2 = 1;

}

}

while(index1 < index2) { index1 = index1 + 10; System.out.println(index1); index2 = index2 * 2; }

ตัวอยางที่ 3 class Loops2 { public static void main(String[] args) { int index = 1;

}

}

while(index != 33) { index++; System.out.println(index); index++; }

การใช break และ continue หลาย ๆ ครั้งที่เราตองการยุติการทํางานของ loop โดยที่ loop ยังไมสิ้นสุดการทํางานของมันเอง เชน กําหนดให loop หยุดการทํางานเมื่อคาของ loop index มีคา ตรงตามเงื่อนไขที่ไดกําหนดไว ดังแสดงให เห็นในโปรแกรมตัวอยางนี้ /* Sum3.java */ import java.io.*; class Sum3 { public static void main(String[] args) { int i, sum; i = 0; sum = 0; do { sum += i; i++; //break out of loop when i >= 50 if(i >= 50) break; }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

87

while(i <= 100);

}

}

System.out.println("Sum = " + sum); System.out.println("Average = " + (double)sum / (i-1));

เราใชโปรแกรม Sum2.java เปนพื้นฐานของการเปลี่ยนแปลง โดยเรากําหนดใหมีการตรวจสอบคาของ i วามากกวาหรือเทากันกับ 50 หรือไมซึ่งถาเปนจริงเราก็จะ break ออกจาก loop ทันที if(i >= 50) break; เมื่อเราลอง run ดูเราไดผลลัพธดังนี้ Sum = 1225 Average = 25.0 ลองมาดูโปรแกรมทีใ่ ช break ในการหยุดการทํางานของ loop ที่ใชหาคาของตัวเลขที่กําหนดใหวา เปน เลขคูจํานวนสิบตัว /* Break.java */ import java.io.*; class Break { public static void main(String[] args) {

}

}

for(int number = 1; ; number++) if(number % 2 == 0) { System.out.println("Number is " + number); //break out of loop when number >= 10 if(number >= 10) break; }

เราจะตรวจสอบวาตัวเลขเปนเลขคูกอนแลวจึงทําการแสดงตัวเลขนั้น ๆ ไปยังหนาจอ เมือ ่ ครบสิบตัวแลว เราก็จะหยุดการทํางานของ loop ดังทีแ ่ สดงใหเห็นจากผลลัพธที่ไดนี้ Number Number Number Number Number

is is is is is

2 4 6 8 10

ทีนี้เรามาลองใช continue ดูบาง /* Continue.java */ import java.io.*; class Continue { public static void main(String[] args) { for(int number = 1; number <= 10; number++) {

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

}

}

}

การประมวลผลแบบวน (Repetition)

88

//skip if number is 5 if(number == 5) continue; System.out.println("Number is " + number);

การประมวลของ code ที่เหลืออยูในโปรแกรมจะถูกประมวลผล ยกเวนเมื่อคาของ number มีคาเทากับ หา ดังแสดงใหเห็นจากผลลัพธนี้ Number Number Number Number Number Number Number Number Number

is is is is is is is is is

1 2 3 4 6 7 8 9 10

การใช continue นั้นโดยทั่วไปมักจะไมคอยมีที่ใชเทาไรนัก เพราะการเขียนโปรแกรมโดยทั่วไปมักจะทํา การประมวลผลกลุมของคําสั่งทั้งหมดจนเสร็จ หรือไมก็ยต ุ ิการทํางานเมื่อเงื่อนไขบางอยางเปนจริง การ กระโดดขามการประมวลผลชุดคําสั่งไมคอยจะมีใหเห็นมากมายนัก ดังนั้นก็คงตองขึ้นอยูกับการออกแบบ โปรแกรมของผูอ  านเองวาเหมาะสมอยางไรตอการใชชุดคําสัง่ ตาง ๆ การใช Nested Loop เราสามารถทีจ ่ ะนําเอา loop ตาง ๆ ที่เราไดพด ู ถึงมาใสไวใน loop ได เชนเดียวกับที่เราทํากับ if – else เนื่องจากวาตัว loop เองก็เปนประโยคอยางหนึ่ง ดังนั้นการนําประโยคมาวางซอนกันในการเขียนโปรแกรม ก็ยอมที่จะทําได เรามาลองดูตัวอยางการใช nested loop กัน /* NestedLoop.java */ import java.io.*; class NestedLoop { public static void main(String[] args) {

}

}

for(int row = 1; row <= 10; row++) { for(int column = 1; column <= 10; column++) { if(column > row) continue; System.out.print("*"); } System.out.println(); }

โปรแกรม NestedLoop.java ของเราใช for loop สองตัวในการแสดงจํานวนของ '*' ในแตละแถว ดังที่ แสดงใหเห็นจากผลลัพธนี้ (หนาถัดไป)

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

89

* ** *** **** ***** ****** ******* ******** ********* ********** ใน for loop ตัวแรกของเรา เราใชตัวแปร row เปน loop index ซึ่งจะประมวลผลเปนจํานวนเทากับสิบ ครั้ง และในแตละครั้งที่ row มีการประมวลผล for loop ตัวที่สองที่มี column เปน loop index จะ ประมวลผลเปนจํานวนเทากับสิบครั้ง เพราะฉะนั้นการประมวลผลของ for loop ทั้งสองตัวจึงมีคาเปน จํานวนเทากับหนึ่งรอยครั้ง ทุก ๆ การประมวลผลของ for loop ตัวทีส ่ องเราจะตรวจสอบวาคาของ column มากกวาคาของ row หรือไม ซึ่งถามากกวาเราจะหยุดการแสดงคา '*' ไปยังหนาจอทันทีดวยการเรียกใช continue ที่เราไดพูด ถึงกอนหนานี้ ในขณะที่ row และ column มีคาเทากับหนึ่งนั้นเราก็สง '*' ไปยังหนาจอ หลังจากนั้น column ก็มีคาเปน สอง ซึ่งมีคามากกวา row การกระโดดขามจึงเกิดขึ้น ซึ่งจะเปนไปจนกระทัง่ column มีคาเทากับสิบเอ็ด การประมวลผลของ for loop ดานในจึงยุตล ิ ง หลังจากนั้น row ก็มีคาเปนสอง เหตุการณเดิมก็เกิดขึ้นอีก แตตอนนี้การแสดงผล '*' จะมีเพิ่มขึ้นจนกวาคาของ column จะมากกวา row เปนเชนนี้ไปเรื่อย ๆ จนกระทั่งคาของ row มีคาเปนสิบเอ็ดการประมวลผลของ for loop ดานนอกจึงยุติลง โดยความเปนจริงแลวเราสามารถที่จะใช break แทนการใช continue ได ซึง่ ก็จะไดผลลัพธเหมือนกัน ทั้งนี้เพราะการใช break จะทําใหเราหลุดออกจาก for loop ดานในทันที ซึง่ เปนการประมวลผลทีด ่ ีกวา การใช continue เนื่องจากวาเราประมวลผล for loop ดานในดวยจํานวนครัง้ ที่เทากับคาของ row ที่ เปนอยูขณะนั้น (ผูอานควรตรวจสอบดูวา การประมวลผลของ for loop ดานในมีจํานวนเทากับกี่ครั้ง ในทุก ๆ การประมวลผลของ for loop ดานนอก - ทุกคาของ row) ตัวอยางการใช nested-loop ในรูปแบบตาง ๆ (ผูอานควรตรวจสอบผลลัพธดวยมือกอนการเขียน โปรแกรมทดสอบ) ตัวอยางที่ 1 class Loops3 { public static void main(String[] args) { int j, k = 0;

}

}

while(k < 3) { j = 5; while(j > 0) { System.out.println(j); j -= 2; } System.out.println("k = " + k); k++; }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

90

ตัวอยางที่ 2 class Loops4 { public static void main(String[] args) { int j, k = 1;

}

}

while(k < 7) { j = 5; while(j > 0) { System.out.println("j = " + j); System.out.println("k = " + k); j--; } k *= 2; }

ตัวอยางที่ 3 class Loops5 { public static void main(String[] args) { int j = 10, k = 1;

}

}

while(k < 8) { while(j > 0) { System.out.println("j = " + j); System.out.println("k = " + k); j--; } k = k * 2; }

การใช Labeled continue และ Labeled break ใน for loop Java ยอมใหมก ี ารใช label ในการหยุดและเริ่มการประมวลผลใหม ซึ่งโปรแกรมเมอรหลาย ๆ ทานไม คอยจะเห็นดวยกับการใชการประมวลผลในลักษณะนี้เทาใดนัก เรามาดูตวั อยางกัน /* LabledContinue.java */ import java.io.*; class LabeledContinue { public static void main(String[] args) {

}

}

label: for(int row = 1; row <= 10; row++) { System.out.println(); for(int column = 1; column <= 10; column++) { if(column > row) continue label; //goto label System.out.print("*"); } }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

91

เราไดดด ั แปลงโปรแกรม Continue.java ของเราสําหรับการแสดงการใช labeled continue ในโปรแกรม LabeledContinue.java เรากําหนดใหมี identifier ที่มช ี ื่อวา label อยูกอนหนา for loop ดานนอกของ เรา ซึ่งตองมีเครื่องหมาย ':' ตามหลังเสมอ และในการใช continue ใน for loop ดานในนัน ้ เราจะตองมี identifier ที่เราใชตามหลัง continue เสมอ การประมวลดวย labeled continue ก็ไมยากนักที่จะทําความเขาใจ เมื่อคาของ column มากกวาคาของ row การทํางานใน for loop ดานในก็สิ้นสุดลงและไปเริ่มตนใหมที่ for loop ดานนอก เพราะนั่นเปนทีท ่ ี่มี label อยู การทํางานแบบนี้ก็เหมือนกับการกระโดดไปยังตําแหนงที่เราตองการจะไปนั่นเอง ทั้งนี้ก็ตอง ขึ้นอยูกับเงื่อนไขที่เราไดตั้งไว ถาเราเปลีย ่ น continue ใหเปน break เราจะไดผลลัพธอะไร เรามาลองดูโปรแกรมที่ใช labeled break กันดู /* LabledContinue.java */ import java.io.*; class LabeledContinue { public static void main(String[] args) {

}

}

System.out.println("Statement before first label."); first: for(int i = 1; i <= 10; i++) { for(int j = 1; j <= 10; j++) { if(j > i) break first; System.out.println('*'); } } System.out.println("Statement after first label.");

เราไดเพิ่มประโยคทั้งกอนและหลัง label ที่ชอ ื่ วา first ของเราเพื่อจะไดดวู า การประมวลผลเกิดขึ้นที่ ใดบาง กอนที่เราจะประมวลผลของประโยคที่ตามหลัง first เราสงขอความไปยังหนาจอวา Statement before first label. และ for loop ของเราทั้งสองตัวสงตัวอักษรเพียงตัวเดียวไปยังหนาจอคือ * หลังจากนั้นก็สง ขอความ Statement after first label. ไปยังหนาจอ จะเห็นวาการใช labeled break นั้นทําใหการประมวลผลของเรายุติลง เพราะวาประโยคที่มี อยูใน block ของ first นั้นมีเพียงประโยคเดียวดังนั้น Java จะประมวลผลประโยคที่อยูถด ั ไป หลังจาก block ของ first ซึ่งก็คือประโยค System.out.println("Statement after first label."); เราสามารถทีจ ่ ะมี label block กี่ block ก็ไดในโปรแกรมของเรา การใช labeled break ถาใชไดอยาง เหมาะสมแลวจะทําใหการเขียน code เปนไปไดอยางสะดวกยิ่งขึ้น ทั้งนี้ก็เพราะวาเราสามารถที่จะ กระโดดไปยัง block ตาง ๆ ไดอยางงาย ๆ ลองมาดูโปรแกรมตัวอยางอีกตัวหนึ่งทีใ่ ช labeled break ในการหาผลคูณของเลขระหวาง 1 – 5

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

92

/* LabledBreak.java */ import java.io.*; class LabeledBreak { public static void main(String[] args) { int prod = 1; int i = 1;

}

}

outer: while(true) { prod *= i; i++; if(i > 5) break outer; } System.out.println("Product = " + prod);

เราใช while loop ทีท ่ ํางานอยูต  ลอดเวลาโดยไมมีการกําหนดใหหยุด (ใช true ใน expression) แตเรา กําหนดใหมีการหยุดจากการใช labeled break ใน while loop เอง ตัวโปรแกรมจะคํานวณหาผลคูณไป จนกวาคาของ i จะเปนหาก็จะ break ออกจาก block ที่ชื่อ outer ทันที และจะไปประมวลผลประโยคที่ อยูถัดมาจาก block ซึ่งก็คือ System.out.println("Product = " + prod) Loop เปนโครงสรางที่ใชมากในการเขียนโปรแกรมตาง ๆ ทั้งนี้เพราะ loop เอื้ออํานวยใหผูเขียนเรียกใช ชุดคําสั่งตาง ๆ ซ้ํากันได ทําใหการเขียนโปรแกรมลดขั้นตอนการทํางานลง และการทํางานของโปรแกรม ก็กระชับยิ่งขึ้น เราจะกลับมาพูดถึง loop อีกหลาย ๆ ครั้งในบทตอ ๆ ไป โดยเฉพาะในเรื่องของ Array และ String สรุป ในบทนี้เราไดพด ู ถึงการใชประโยคของการเปรียบเทียบ และการตัดสินใจ การใชประโยคควบคุมการ ทํางาน การใช loop ในการประมวลผลติดตอกัน โดยรวมแลวเราไดพูดถึง 9 9 9 9 9 9

การใช การใช การใช การใช การใช การใช

if และ if-else nested-if Tertiary operator - ? : switch loop ตาง ๆ เชน for-loop while-loop และ do-while-loop break continue และการใชประโยคทีใ่ ช label

แบบฝกหัด 1. จงเขียนโปรแกรมทีร่ ับ int จาก keyboard จํานวน 10 ตัว หลังจากนั้นใหคาํ นวณหาผลรวม และ คาเฉลีย ่ ของขอมูลทั้ง 10 ตัว ใหสงผลลัพธออกทางหนาจอ 2. จงเขียนโปรแกรมทีส ่ รางตัวเลขแบบสุมจํานวน 100 ตัว เสร็จแลวใหแสดงผลลัพธออกทางหนาจอ เฉพาะตัวเลขทีเ่ ปนเลขคี่เทานัน ้ โดยกําหนดใหการแสดงผลเปน 10 ตัวตอหนึ่งบรรทัด 3. จากโจทยในขอ 2 แทนทีจ ่ ะแสดงผลเปนเลขคี่ใหแสดงผลเฉพาะที่เปนเลขคูเทานั้น โดยแสดงเฉพาะ เลขคูที่มากกวา 20 เทานั้น 4. จงเขียนโปรแกรมทีแ ่ สดงตัวอักษรตั้งแต A ไปจนถึง Z ดวยการใช while loop โดยไมมีการรับคาใด ๆ จาก keyboard

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

93

5. จงเขียนโปรแกรมทีค ่ ํานวณหาคาที่เล็กทีส ่ ุดในกลุมตัวอักษรที่อานเขามาจาก keyboard ทีละตัว (ตัวอักษรที่นําเขาควรมีจํานวนไมนอยกวา 10 ตัว) 6. จงเขียนโปรแกรมที่อานขอมูล 2 ตัวจาก keyboard โดยทีต ่ วั แรกเปน หมายเลขของสินคา (product number) และตัวทีส ่ องเปน จํานวนที่ขายไปในแตละวัน (quantity sold) กําหนดใหมีสินคาอยู 5 ชนิดที่มีราคาตางกัน ดังนี้ สินคาที่ สินคาที่ สินคาที่ สินคาที่ สินคาที่

1 2 3 4 5

ราคา ราคา ราคา ราคา ราคา

500.0 บาท 750.0 บาท 850.0 บาท 950.0 บาท 1000.0 บาท

โปรแกรมจะคํานวณหายอดเงินที่ขายไดของสินคาทุกตัว ในอาทิตยทผ ี่ านมา โดยที่จํานวนของสินคา แตละชนิดที่ขายไปจะนําเขามาจาก keyboard โปรแกรมที่เขียนขึ้นตองใช switch ในการแยกแยะ ราคาของสินคาแตละชนิดที่เขามา ใหแสดงผลลัพธออกทางหนาจอ 7. จงเขียนโปรแกรมทีค ่ ํานวณหาดอกเบี้ยทบตนจากเงินตนที่อานเขามาจาก keyboard ดวยสูตรที่ กําหนดให ตอไปนี้ (คลาย ๆ กับตัวอยางในบทนี้) a = p(1 + r)n p หมายถึงเงินลงทุนครั้งแรก r หมายถึงอัตราดอกเบี้ยตอป n หมายถึงจํานวนปที่ตองการฝากเงิน a จํานวนเงินทีฝ ่ ากเขาทุก ๆ สิ้นป โปรแกรมควรแสดงรายการออกเปนสอง column โดยที่ column แรกเปนปที่ฝาก และ column ที่ สองเปนดอกเบี้ยที่ไดในแตละป ใหทดลอง run โปรแกรมดวยอัตราดอกเบี้ย 5% ตอป และเงินตนที่ 1000 บาท เปนเวลา 10 ป 8. จงเขียนโปรแกรมทีแ ่ สดงผลลัพธ ดังที่เห็นนี้ ดวยการใช loop เทานั้น ********** ********* ******** ******* ****** ***** **** *** ** *

********** ********* ******** ******* ****** ***** **** *** ** *

9. จงเขียนโปรแกรมทีร่ ับคา int หนึ่งตัว (n) ที่มากกวาศูนย หลังจากนั้นใหแสดงผล ดังนี้ 1 2 3 … n-1 n 1 2 3 … n-1 … 123 12 1

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

94

10. จงเขียนโปรแกรมทีร่ ับคาเปน วัน เดือน ป จาก keyboard หลังจากนั้นใหแสดงตําแหนงของวันที่นั้น ในป เชน 12 29 2002 จะแสดงเปน 363 11. จงเขียนโปรแกรมทีร่ ับคาตาง ๆ จาก keyboard เฉพาะที่เปน 0 มากกวาศูนย และ นอยกวาศูนย ให นับจํานวนของคาทั้งสามวามีอยางละกี่ตวั โปรแกรมจะหยุดทํางานไดก็ตอ  เมื่อ user ใสขอมูลที่ไมใช ตัวเลข 12. จงเขียนโปรแกรมทีร่ ับคาระหวาง 1 – 100 หลังจากนั้นใหแสดงคาทีร่ ับเขามาในรูปแบบของ ตัวหนังสือ เชน ถาขอมูลนําเขาเปน 11 ผลลัพธที่ไดคือ สิบเอ็ด 13. จงเขียนโปรแกรมทีท ่ ําการเขารหัสของขอมูลที่นําเขาจาก keyboard โดยนําเอาตัวอักษรที่อานเขา บวกกับคาของตัวอักษรที่อยูถด ั ไป 2 ตัวอักษร mod ดวยจํานวนของตัวอักษรที่มีอยู (26 ใน ภาษาอังกฤษ) เชน ถาคานําเขาเปน a ผลลัพธที่ไดจากการเขารหัสจะเปน a + c ซึ่งจะมีคา เทากับ 97 + 99 = 196 % 26 = 14 ใหใชคานี้เปนตัวบอกตําแหนงของตัวอักษรทีจ ่ ะแสดงไปยังหนาจอ ซึ่ง ตัวอักษร ณ ตําแหนงที่ 14 นีค ้ อ ื n 14. จงเขียนโปรแกรมทีร่ ับคาเปนประโยคทางคณิตศาสตร เชน 9 + 5 – 2 * 4 + 2 / 3 หลังจากนั้นให ทําการประมวลผลประโยคดังกลาว ตามลําดับของขอมูลที่นาํ เขา 15. จงเขียนโปรแกรมทีร่ ับคาเดือนที่เปนตัวเลขระหวาง 1 – 12 หลังจากนั้นใหแสดงผลเปนจํานวนของ วันที่มีอยูใ นเดือนดังกลาว 16. จงหาผลลัพธของตัวแปร sum จาก code ที่ให class Loops6 { public static void main(String[] args) { int j = 0, k, m, n, sum = 0;

} }

while(j != 20) { k = 0; while(k != 100) { m = 0; while(m != 50) { n = 0; while(n != 10) { sum++; n++; } m++; } k++; } j++; }

17. จงเขียนโปรแกรมทีค ่ ํานวณหา ตัวหารรวมมาก (GCD – Greatest Common Divisor) ของตัวเลข สองตัวที่รับเขามาจาก keyboard เชน gcd ของ 24 และ 15 คือ 3 note: gcd ของ x และ y คือ integer ที่ใหญที่สด ุ ที่หาร x และ y ลงตัว (เหลือเศษ 0) 18. จงเขียนโปรแกรมทีค ่ ํานวณหา ตัวคูณรวมนอย (LCD – Least Common Multiple) ของตัวเลขสอง ตัวทีร่ ับเขามาจาก keyboard เชน lcd ของ 24 และ 15 คือ 120 note: lcd ของ x และ y คือ integer ที่นอยที่สด ุ ที่ทั้ง x และ y หารลงตัว

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 3 เริ่มตนกับ Java

การประมวลผลแบบวน (Repetition)

95

19. จงเขียนโปรแกรมทีห ่ า factor ของตัวเลขที่รับเขามาจาก keyboard เชน ถาขอมูลเทากับ 18 factor ที่ไดคือ 2 3 และ 3 (8 = 2 * 3 * 3)

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


ในบทนี้เราจะมาดูการสรางและใช array ซึ่งเปนโครงสรางอีกตัวหนึ่งที่ทําใหเราสามารถเก็บขอมูลที่เปน ชนิดเดียวกันหลาย ๆ ตัวไวในตัวแปรตัวเดียว รวมไปถึงการสรางและใช string ซึ่งจะเปนการแนะนําให ผูอานไดรจ ู ักกับ object ในภาษา Java แบบคราว ๆ หลังจากจบบทเรียนนี้แลว ผูอา นจะไดทราบถึง o o o o o o

การประกาศและกําหนดคาให array การเขาหาขอมูลในตําแหนงตาง ๆ ที่อยูใน array การสราง array ที่ใชเก็บ array การสราง object ที่เปน string การสรางและใช array ที่เก็บ object การใชกระบวนการตาง ๆ กับ object ที่เปน string

การใช array Array เปนโครงสรางชนิดหนึ่งที่ประกอบไปดวยขอมูลชนิดเดียวกันที่อาจมีมากกวาหนึ่งตัว การเขาหา ขอมูลแตละตัวที่อยูใน array จะตองทําผานทาง ชื่อของ array และ index ที่มีคาเปน integer (int) ประกอบกัน Java ไดกําหนดให index ตัวแรกสุดที่เก็บขอมูลมีคาเปน 0 และจะเพิ่มขึ้นทีละหนึ่งคาไป เรื่อย ๆ จนกวาจะหมดขอมูลทีม ่ ีอยูใน array นั้น ๆ การประกาศตัวแปรที่เปน array ทําไดดงั นี้ datatype[] nameOfArray; เชน int[] listOfNumbers; double[] prices; char[] vowels; ในการประกาศ array นั้นเราจะตองกําหนดจํานวนของขอมูลสูงสุดที่ array นั้นสามารถเก็บได ชนิดของ ขอมูลที่จะเก็บไวใน array นั้น เครื่องหมาย [] เปนตัวบอกให Java รูวาตัวแปรที่ถูกสรางขึ้นมานี้เปน array และเครือ ่ งหมายนี้ก็จะเปนตัวทีใ่ ชในการเขาหาขอมูลแตละตัวใน array หนังสือหลาย ๆ เลมเลือกที่ จะประกาศ array ในรูปแบบทีเ่ ห็นดานลางนี้ ซึ่งมีความหมายเหมือนกันกับที่เราไดประกาศกอนหนานี้ int listOfNumbers[]; double prices[]; char vowels[]; สําหรับหนังสือเลมนี้เราจะใชการประกาศในแบบที่หนึ่ง หลังจากที่เราไดประกาศใหตัวแปรเปน array แลวเราก็ตองกําหนดความจุใหกับ array นั้น ดังนี้ listOfNumbers = new int[5];


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

97

ประโยคที่เราไดเขียนขึ้นนั้นบอกให Java รูวาเราตองการให Java จองเนื้อที่ในการเก็บ int เปนจํานวน เทากับ 10 ตัวใหกับตัวแปร listOfNumbers ซึ่งตัวแปรนี้จะเปนตัวอางอิง (reference) ถึงขอมูลทั้งหมดที่ ไดถูกเก็บไวใน array นี้ ภาพที่ 4.1 แสดงถึงสิ่งตาง ๆ ที่เกิดขึ้นเมื่อเราประกาศการใช array

ชนิดของขอมูลที่ array num เก็บได

ชื่อของ array

ประกาศ array ที่ เก็บ int

int [] num = new int[5]; ใช operator new ในการจองเนื้อที่ ชนิด int จํานวน 5 ตัว

index ของ array num num[0]

num[1]

num[2]

num[3]

num[4]

num.length จะมีคาเทากับ 5

ภาพที่ 4.1 การประกาศและกําหนดขนาดของ array

เมื่อมีการประกาศใช array เชน int [] num; นั้น array ที่เราไดประกาศนั้นยังไมมีเนื้อที่ในหนวยความจําเลย เราตองกําหนดขนาดเพื่อใหเกิดการจอง เนื้อที่ในหนวยความจําดวยการใช operator new รวมไปถึงจํานวนของเนื้อที่ทต ี่ องการใช เชน int [] num = new int[5]; และทุกครั้งของการจองเนื้อที่ Java จะกําหนดใหขอมูลในทุก ๆ ตําแหนงมีคาเปน 0 เสมอ ในการเขาหาขอมูลแตละตัวนัน ้ เราก็เพียงแตกําหนด index ของขอมูลที่เราตองการเขาหา เชน num[3] num[2] เราไมสามารถเขาหาขอมูล ณ ตําแหนงที่มค ี า index เกิน 4 ไดทั้งนี้เพราะเรากําหนดให array num มี ความจุสูงสุดเทากับ 5 ดังนั้นคาของ index ทีเ่ ปนไปได คือ 0 1 2 3 และ 4 ถาหากวาเราเขาหาขอมูลที่ ไมอยูในตําแหนงที่กลาวนี้ Java จะฟองดวย error ทันที (array index out of bound) การกําหนดคาเบื้องตนใหกบ ั array เรารูวาหลังจากการประกาศและจองเนื้อที่ใหกบ ั array นั้นถาเปน array ที่เก็บ int ทุก ๆ หนวยความจํา ของ array จะมีคาเปน 0 แตถาเราตองการใหเปนคาอื่นเราก็สามารถทําได ดังโปรแกรมตัวอยางนี้ /* Array1.java */ import java.io.*; class Array1 {

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

98

public static void main(String[] args) { int[] list; //declare array of int

}

}

list = new int[10]; //allocate space for 10 ints for(int i = 0; i < list.length; i++) System.out.println("list[" + i +"] = " + list[i]);

โปรแกรม Array1.java ประกาศใหตัวแปร list เปน array ที่เก็บ int เปนจํานวนเทากับ 10 ตัว เมื่อ ประกาศเสร็จแลว เราก็ใช for loop ในการเขาหาขอมูลในแตละตัว array โดยแสดงถึงคาที่ Java กําหนด ใหกับ array ของเราไปยังหนาจอ ซึ่งมีคาดังนี้ list[0] list[1] list[2] list[3] list[4] list[5] list[6] list[7] list[8] list[9]

= = = = = = = = = =

0 0 0 0 0 0 0 0 0 0

การใช loop เปนวิธีการที่งา ยทีส ่ ุดในการเขาหาขอมูลทุกตัวทีอ ่ ยูใน array ยกเวนวาเรารูตาํ แหนงที่ แนนอนของขอมูลที่เราตองการใน array นั้น เชน ตําแหนงที่ 5 หรือตําแหนงที่ 3 เราก็เขาหาไดโดยตรง ดังนี้ list[5] หรือ list[3] เปนตน Array ทีส ่ รางขึน ้ ใน Java นั้นเราสามารถที่จะดึงเอาขนาดของ array ออกมาไดดวยการเรียกใชคาคงทีท ่ ี่ ไดถูกสรางขึ้นหลังจากการประกาศและจองเนื้อที่ใหกับ array ดังนี้ list.length; ทุก array ที่ไดถูกสรางขึ้นจะมีขนาดของ array เก็บไวในตัวแปรชื่อ length และเราเรียกขนาดออกมาได ผานทางชื่อของ array ตามดวย . และตัวแปร length เรามาลองกําหนดคาในตําแหนงตาง ๆ ใหกบ ั array ของเรา /* Array2.java */ import java.io.*; class Array2 { public static void main(String[] args) { int[] list; //declare array of int

}

}

list = new int[10]; //allocate space for 10 ints list[5] = 8; list[3] = 2; list[9] = 4; for(int i = 0; i < list.length; i++) System.out.println("list[" + i +"] = " + list[i]);

ผลลัพธที่ไดจากการ run คือ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

list[0] list[1] list[2] list[3] list[4] list[5] list[6] list[7] list[8] list[9]

= = = = = = = = = =

การใช Array และ String

99

0 0 0 2 0 8 0 0 0 4

เราสามารถทีจ ่ ะกําหนดคาใหกับ array โดยที่ไมตองกําหนดขนาดใหกับ array โดยตรง แตให Java จัดการเกี่ยวกับเรื่องเนื้อที่ใหเรา ดังโปรแกรมตัวอยางตอไปนี้ /* Array3.java */ import java.io.*; class Array3 { public static void main(String[] args) { int[] list = {2, 3, 1, 56, 90};

}

}

for(int i = 0; i < list.length; i++) System.out.println("list[" + i +"] = " + list[i]);

เรากําหนดให list เปน array ที่เก็บ int และกําหนดคาเบื้องตนเปน 2 3 1 56 และ 90 ตามลําดับ เมื่อ Java เห็นการประกาศในลักษณะนี้ก็จะทําการจองเนื้อที่ใหกบ ั array โดยอัตโนมัติพรอมทัง้ นําคาตาง ๆ ที่ ไดถูกกําหนดจาก user ไปใสไวใน array list และเมื่อ run ดูเราก็ไดผลลัพธดังที่เห็นนี้ list[0] list[1] list[2] list[3] list[4]

= = = = =

2 3 1 56 90

โปรแกรมตัวอยางตอไปนี้แสดงถึงการเก็บขอมูลที่ user ใสเขามาจาก keyboard เขาสู array /* ArrayOfNumbers.java */ import java.io.*; import java.text.DecimalFormat; import java.lang.Integer; class ArrayOfNumbers { public static void main(String[] args) throws IOException { double number, sum = 0; //a number read and sum of numbers double[] list; //array of double int count; //number of items in array String input; //input string BufferedReader buffer; //input buffer InputStreamReader isr; //input stream DecimalFormat f = new DecimalFormat("0.00"); System.out.print("How many numbers? : "); isr = new InputStreamReader(System.in); buffer = new BufferedReader(isr);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

100

input = buffer.readLine(); count = Integer.parseInt(input); //total items in list list = new double[count]; //allocate space forlist //reading each double into list for(int i = 0; i < list.length; i++) { System.out.print("Enter number: "); input = buffer.readLine(); list[i] = Double.parseDouble(input); } //add all doubles in list int n = list.length - 1; //n is the last index of list while(n >= 0) { //looping until n equals to 0 sum += list[n--]; //add list[n] into sum and } //decrement n

}

}

//calculate average and display result double average = sum / count; System.out.println("Sum of numbers = " + sum); System.out.println("Average of numbers = " + f.format(average));

โปรแกรม ArrayOfNumbers.java ถาม user ถึงจํานวนของขอมูลสูงสุดที่ user จะใสเขาสูโ ปรแกรม ซึ่ง เมื่อไดแลวโปรแกรมจะใชจํานวนที่อานไดเปนตัวกําหนดขนาดใหกับ array list = new double[count]; หลังจากนั้นก็จะอานขอมูลทีละตัวจาก user นําไปเก็บไวใน array list for(int i = 0; i < list.length; i++) { System.out.print("Enter number: "); input = buffer.readLine(); list[i] = Double.parseDouble(input); } ในขณะที่อานขอมูลเขาสู array นั้นเราอาจหาผลรวมของเลขทุกตัวพรอม ๆ กันไปดวยก็ได แตที่ โปรแกรมนีแ ้ ยกการหาผลรวมก็เพื่อที่จะแสดงใหเห็นถึงการใช loop ในการเขาหา array อีกครั้งหนึ่ง โดย เรากําหนดใหตวั แปร n เปน index ตัวสุดทายของ array list ดวยประโยค int n = list.length - 1; เราตองไมลืมวา list.length ใหจํานวนของขอมูลทั้งหมดทีอ ่ ยูใน array ดังนั้น index ตัวสุดทายก็คือ list.length – 1 หลังจากนั้นเราจะใช while loop เปนตัวเขาหาขอมูลใน array แตละตัวจากขางหลัง และ บวกขอมูลทุก ๆ ตัวเขากับตัวแปร sum while(n >= 0) { sum += list[n--]; } ประโยค sum += list[n--] นั้นจะบวกขอมูลในตําแหนง n เขากับตัวแปร sum กอนที่จะลดคาของ n ลง หนึ่งคา และเมือ ่ คา n นอยกวา 0 เราก็หลุดออกจาก while loop ทันที

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

101

การอางถึง array ดวยการ clone และการ copy array เมื่อเราสราง array ขึ้นมาแลวเราสามารถที่จะอางถึงตัวแปรตัวนี้ดวยตัวแปรอืน ่ ก็ได แตไมไดหมายความ วาเราไดสราง array ตัวใหมจากตัวแปรตัวใหมนี้ เราเพียงแตใชตวั แปรตัวใหมในการอางถึง array ตัวเดิม เพราะฉะนั้นการกระทําใด ๆ ผานตัวแปรตัวใหมก็จะมีผลกระทบกับขอมูลใน array ตัวเดิมนั้น ดังโปรแกรม ตัวอยางนี้ /* Array4.java */ import java.io.*; class Array4 { public static void main(String[] args) { int[] list = {2, 3, 1, 56, 90}; for(int i = 0; i < list.length; i++) System.out.println("list[" + i +"] = " + list[i]);

}

}

int[] newList = list; //cloning newList[0] = 11; //changing data at list[0] for(int i = 0; i < list.length; i++) System.out.println("list[" + i +"] = " + list[i]);

เราไดดด ั แปลงโปรแกรม Array3.java ใหมีการอางถึง (reference) array list ดวยตัวแปรตัวใหมทช ี่ ื่อ newList int[] newList = list; และเราก็ไดทําการเปลี่ยนขอมูล ณ ตําแหนง 0 ใหเปน 11 ผานทาง newList เมื่อลอง run ดูเราก็จะได ผลลัพธดังทีค ่ าดไว list[0] list[1] list[2] list[3] list[4]

= = = = =

2 3 1 56 90

list[0] list[1] list[2] list[3] list[4]

= = = = =

11 3 1 56 90

สวนวิธีการ copy ขอมูลจาก array ตัวหนึ่งไปยัง array อีกตัวหนึ่งนั้นมีวิธีการอยูส  ามวิธท ี ท ี่ ําได วิธท ี ี่หนึง่ นั้นเราตองสราง array ใหมขึ้นมาแลวก็ copy ขอมูลทุกตัวจาก array ตัวเดิมเขาสู array ตัวใหม ดังนี้ /* Array5.java */ import java.io.*; class Array5 { public static void main(String[] args) { int[] list = {2, 3, 1, 56, 90}; int[] newList = new int[list.length];

//original array //new array

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

102

//copy each item from list into newList for(int i = 0; i < list.length; i++) newList[i] = list[i]; for(int i = 0; i < list.length; i++) System.out.println("newList[" + i +"] = " + newList[i]); }

}

โปรแกรม Array5.java สราง newList ดวยคําสั่ง int[] newList = new int[list.length]; เรากําหนดขนาดของ newList ดวยขนาดที่มาจาก list หลังจากนั้นเราก็ copy ขอมูลทุกตัวดวยการใช for – loop for(int i = 0; i < list.length; i++) newList[i] = list[i]; และเมื่อ run ดูเราก็ไดผลลัพธดังทีค ่ าดไว คือ newList[0] newList[1] newList[2] newList[3] newList[4]

= = = = =

2 3 1 56 90

ทีนี้เรามาดูวิธท ี ส ี่ องกัน /* Array6.java */ import java.io.*; class Array6 { public static void main(String[] args) { int[] list = {2, 3, 1, 56, 90}; int[] newList = new int[list.length];

//original array //new array

//copy each item from list into newList System.arraycopy(list, 0, newList, 0, list.length); for(int i = 0; i < newList.length; i++) System.out.println("newList[" + i +"] = " + newList[i]); }

}

ถึงแมวาเรายังไมไดพูดถึงเรื่องของ class หรือ method แตเราก็ตองมาทําความเขาใจถึงการเรียกใช method ที่ Java มีให เพราะวาวิธีทส ี่ องนี้เราใช method arraycopy() ทําการสรางและ copy ขอมูลให ตอนนี้เราคงตองจําวิธีการเรียกใชมากกวาการทําความเขาใจอยางละเอียด (ซึ่งเราจะพูดถึงในบทตอ ๆ ไป) เรา copy ดวยการใชคําสัง่ System.arraycopy(list, 0, newList, 0, list.length); โดยเราตองใสขอมูล หรือ เงื่อนไข (parameter) ตามที่ Java กําหนดไวคอ ื

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

ตัวแรกเปน array ตัวเดิมทีต ่ องการ copy ตัวทีส ่ องเปน index เริ่มตนของ array ตัวเดิม ตัวทีส ่ ามเปน array ตัวใหมทต ี่ องการสราง ตัวทีส ่ ี่เปน index เริ่มตนของ array ตัวใหม ตัวทีห ่ าเปน จํานวนของขอมูลที่ตองการ copy

103

(list) (0) (newList) (0) (list.length)

วิธีทส ี่ ามก็คลาย ๆ กับวิธีทส ี่ องเพียงแตเราเรียกใช method clone() แทน ซึ่งทําไดดังนี้ /* Array7.java */ import java.io.*; class Array7 { public static void main(String[] args) { int[] list = {2, 3, 1, 56, 90};

//original array

//cloning process int[] newList = (int[])list.clone(); for(int i = 0; i < list.length; i++) System.out.println("newList[" + i +"] = " + newList[i]); }

}

เราเพียงแตเรียกใช method clone() ดังที่เห็นในโปรแกรม Array7.java เราก็สามารถที่จะมี array ตัว ใหมสําหรับการใชงาน ดวยประโยค int[] newList = (int[])list.clone(); เราจําเปนทีจ ่ ะตองทําการ cast ใหกับ array ของเราเสียกอนเพื่อใหชนิดของ array ที่ถูก clone ขึ้นมานั้น เปนชนิดเดียวกัน ซึ่งทําไดดวยการนําเอา (int[]) ไปใสไวหนาประโยค list.clone() ทั้งนี้ตองกําหนดชื่อ array ตัวเดิมใหถูกตอง (list) เพื่อไมใหเกิดการผิดพลาดใด ๆ วิธีทส ี่ ามที่ไดกลาวไวจะ copy ขอมูลใน array เดิมที่มีอยูท  ั้งหมดไปเก็บไวใน array ตัวใหม ดังนั้น ถา หากวาเราตองการที่จะสราง array ใหมจากขอมูลบางสวนของ array ตัวเดิมเราก็ตองใชวธ ิ ีที่สอง ดัง ตัวอยางนี้ /* Array8.java */ import java.io.*; class Array8 { public static void main(String[] args) { int[] list = {2, 3, 1, 56, 90}; //original array int[] newList = new int[list.length-2]; //new array //copy item at index 2, 3, and 4 from list into newList System.arraycopy(list, 2, newList, 0, list.length – 2);

}

}

for(int i = 0; i < newList.length; i++) System.out.println("newList[" + i +"] = " + newList[i]);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

104

โปรแกรม Array8.java ของเราตองการที่จะ copy ขอมูล ณ ตําแหนงที่ 2 3 และ 4 จาก array list เขาสู array newList ในตําแหนง 0 1 และ 2 ตามลําดับ เพราะฉะนัน ้ เราตองเรียกใช method arraycopy() ดังนี้ System.arraycopy(list, 2, newList, 0, list.length – 2); ผลลัพธของการ run คือ newList[0] = 1 newList[1] = 56 newList[2] = 90 การใช array แบบยืดหยุน (Dynamic Array) เราสามารถทีจ ่ ะใชเทคนิคที่เราพูดมากอนหนานี้ในการสราง array แบบไมจาํ กัดจํานวนของขอมูลที่ สามารถจัดเก็บไดใน array นั้น ๆ เราเรียกการจัดเก็บแบบนี้วา การจัดเก็บแบบยืดหยุน แตกอนที่เราจะ สรางไดนั้นเราตองกําหนดให array เริ่มตนของเรามีขนาดเบื้องตนกอน หลังจากนั้นจึงจะสามารถขยาย ขนาดของ array ได ดังโปรแกรมตัวอยางที่ไดดัดแปลงมาจากโปรแกรม AddNumbers.java ที่เขียนขึ้น กอนหนานี้ /* DynamicArray.java */ import java.io.*; import java.text.DecimalFormat; class DynamicArray { public static void main(String[] args) throws IOException { double number, sum = 0; //a number read and sum of numbers double []list = new double[2]; //array of double int count = 0; //total numbers read BufferedReader buffer; //input buffer InputStreamReader isr; //input stream StreamTokenizer token; //token from input stream DecimalFormat f = new DecimalFormat("0.00"); System.out.print("Enter numbers (space between – enter when done): "); isr = new InputStreamReader(System.in); buffer = new BufferedReader(isr); //get tokens from input buffer token = new StreamTokenizer(buffer); //set priority to EOL so that we can break out of the loop token.eolIsSignificant(true); //get each number from tokens //calculate the sum until EOL is reached while(token.nextToken() != token.TT_EOL) { switch(token.ttype) { //token is a number case StreamTokenizer.TT_NUMBER: //double the size of list if(count > list.length-1) { double []newList = new double[list.length*2]; System.arraycopy(list, 0, newList, 0, list.length); list = newList; //point to new list } list[count] = token.nval; //save token into list

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

105

sum += list[count]; //calculate sum count++; //number of tokens read break; default: System.out.println("Token is not a number! "); break;

}

}

} } //calculate average and display result double average = sum / count; System.out.println("Sum of numbers = " + sum); System.out.println("Average of numbers = " + f.format(average));

เราประกาศตัวแปร list ใหเปน array ที่เก็บ double เริ่มตนดวยจํานวนเทากับ 2ตัว และในการนําขอมูล เขาสู array นั้นเราจะตรวจสอบดูวาจํานวนของ index ที่เราใชในการเขาหาขอมูลแตละตัวมีคาเกินจํานวน ของขอมูลที่เปนอยูขณะนั้นหรือไม ซึ่งถาเปนจริงเราก็จะทําการขยายขนาดใหกับ array list เปนจํานวน สองเทาของขนาดเดิม และทําการ copy ขอมูลจาก array list ไปสู array ใหมนี้ (newList) หลังจากนั้น เราก็อางถึง array ตัวใหมนี้ดว ยตัวแปรเดิมที่เราใชในการเก็บขอมูลครั้งแรก (list) เราไมตองกังวลถึง หนวยความจําที่เราไดใชไปในการสราง array ตัวเดิมเพราะ Java จะทําการตรวจสอบถึงหนวยความจําที่ ไมมีการใชงาน และจะคืนหนวยความจํานี้ใหกบ ั ระบบโดยอัตโนมัติ if(count > list.length-1) { double []newList = new double[list.length*2]; System.arraycopy(list, 0, newList, 0, list.length); list = newList; } วิธีการขยายขนาดของ array แบบนี้ทําใหเราไมตองกําหนดขนาดของ array ใหมีขนาดใหญมากมาย เกินไปตอนที่เราสราง array ในครั้งแรก เราสนใจเฉพาะเมื่อจําเปนตองขยายขนาดของ array จริง ๆ เทานั้น ผูอานอาจเปลี่ยนแปลงการขยายขนาดของ array ดวยการเพิ่มทีละกีต ่ ัวก็ได ทั้งนี้กข ็ ึ้นอยูกับความ จําเปนและเหมาะสมกับงานนัน ้ ๆ ผลลัพธของการ run โปรแกรม DynamicArray.java Enter numbers (space between - enter when done): 15 5 20 15 10 15 20 Sum of numbers = 100.0 Average of numbers = 14.29 โปรแกรมตัวอยางการใช array ในการนับจํานวนครั้งของลูกเตาที่ออกซ้ํากันจากการโยนหลาย ๆ ครั้ง /* DiceRolling.java */ import java.io.*; class DiceRolling { public static void main(String[] args) { int face, roll; int[] frequency = new int[7];//number of times each face occur //rolling the die for 100 times roll = 1; while(roll <= 100) { //calculate face of die face = (int)(Math.random() * 6) + 1;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

}

การใช Array และ String

106

//save each time the same face occur by using //indeces as faces of die frequency[face]++; roll++;

System.out.println("Face\tFrequency"); for(int i = 1; i < frequency.length; i++) System.out.println(i + "\t" + frequency[i]); }

}

โปรแกรม DiceRolling.java ใชตัว index ของ array เปนหนาของลูกเตาที่ถูกโยนโดยการใชการสุม ผาน ทาง method random() ซึ่งจะบังคับใหผลลัพธของการโยนนั้นอยูระหวาง 1 – 6 ดวยการคูณ 6 เขากับ ผลลัพธที่ไดจากการสุม บวกเขากับ 1 การนับจํานวนครั้งก็ทําไดดวยการเพิ่มคาใหกับขอมูลที่ index นั้น ๆ ของลูกเตา เชน ถาการโยนไดคาเทากับ 6 เราก็เพิ่มคาดวย frequency[6]++ ซึ่งจะทําใหคาที่อยู ณ ตําแหนงนั้นเพิม ่ ขึ้นอีกหนึ่งคา วิธีการใช index ของ array ในลักษณะนี้ชวยลดขั้นตอนการนับจํานวนของ หนาลูกเตาที่เกิดขึ้น ไดดีกวาวิธีอื่น ๆ เชน การใช if – else มาชวยในการตรวจสอบวาการโยนใหคาอะไร แลวจึงเพิ่มคาใหกับตัวแปรที่เก็บการนับของหนานั้น ๆ if(face == 1) count1++; else if(face == 2) count2++; else if(face == 3) count3++; … … else if(face == 6) count6++; ซึ่งเปนวิธีที่ตองเขียน code มากกวาและใชตวั แปรเยอะกวา การใช frequency[face]++ ผลลัพธของการ run Face 1 2 3 4 5 6

Frequency 12 25 24 7 12 19

การคนหาขอมูลใน array การคนหาขอมูลใน array นั้นทําไดอยูส  องวิธีใหญ ๆ คือ การคนหาแบบตามลําดับ (sequential search) และ การคนหาแบบหารสอง (binary search) เราจะมาดูถึงวิธีการคนหาแบบตามลําดับกอน เพราะเปน การคนหาที่งายทีส ่ ุด การคนหาแบบตามลําดับ (Sequential search) ในการคนหาแบบนี้นั้นเราจะเริม ่ ตนจากขอมูลตัวแรกสุดที่อยูใ น array ทําการเปรียบเทียบขอมูลตัวนี้กับ ขอมูลที่ตองการคนหาวาเปนตัวเดียวกันหรือไม ถาใชเราก็หยุดการคนหา ถาเราคนไปจนถึงตัวสุดทายแต ก็ยังไมใช เราก็รูวาขอมูลที่ตองการคนหาไมไดอยูใน array ลองดูโปรแกรมตัวอยางกัน

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

107

/* SeqSearch.java */ import java.io.*; class SeqSearch { public static void main(String[] args) { int[] list = {2, 3, 1, 56, 90};; int number = 90; //number to search int i = 0; //loop index boolean notFound = true; //loop control variable while(notFound) { if(number == list[i]) //if found notFound = false; //break out of loop i++; //move to next number } //in the list

}

}

if(!notFound) System.out.println(number + " is in the list."); else System.out.println(number + " is not in the list.");

เราใช while loop ในการเขาหาขอมูลทุกตัวทีอ ่ ยูใน array list โดยเรากําหนดใหตัวแปร notFound ซึ่งมี ชนิดเปน boolean เปนตัวควบคุมการทํางานของ loop ซึ่งถาการคนหาประสพผลสําเร็จ ตัวแปร notFound ก็จะถูกกําหนดใหเปน false และ while loop ของเราก็จะยุติการทํางานทันที หลังจากนั้นเราก็ แสดงผลของการคนหาไปยังหนาจอ ดังตัวอยางของการคนหาเลข 90 จากโปรแกรมของเรานี้ 90 is in the list. ถาหากวาเราไมตองการใช boolean เปนตัวกําหนดการทํางานของ loop เราก็อาจกําหนดให loop ทํางาน ไปเรื่อย ๆ และใชคาํ สั่ง break เปนตัวกําหนดการหยุดก็ได โดยการเปลีย ่ น code ใหเปน /* SeqSearch2.java */ import java.io.*; class SeqSearch2 { public static void main(String[] args) { int[] list = {2, 3, 1, 56, 90}; int number = 90; //number to search int i = 0; //loop index while(true) { if(number == list[i]) //if found break; //break out of loop i++; //move to next number } //in the list

}

}

if(i >= list.length) System.out.println(number + " is not in the list."); else System.out.println(number + " is in the list.");

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

108

เรารูวาถาขอมูลที่ตองการคนหาไมอยูใน list ตัวแปร i จะมีคา เกินกวาจํานวนของขอมูลที่มอ ี ยูใน array ดังนั้นการแสดงผลจะตองใชการเปรียบเทียบคาของ i กับจํานวนของขอมูลที่มีอยูใน array (แทนการ เปรียบเทียบดวย boolean กอนหนานี้) วิธีการตรวจสอบแบบนี้ลดขั้นตอนการทํางานของ loop ลงไปได หนึ่งครั้ง เพราะเราจะ break ออกจาก loop ทันที ที่เราคนหาขอมูลเจอ การคนหาแบบนี้ไมคอยนิยมใชกันมากเทาไร ทั้งนี้ก็เพราะวาจะใชเวลาในการคนหามาก ถาขอมูลที่ ตองการคนหาอยูดานหลังสุดของ array ยิ่งถา array เก็บขอมูลไวเยอะการคนหาก็จะใชเวลามากยิ่งขึ้น การคนหาแบบหารสอง (Binary search) การคนหาในรูปแบบของ binary search จะทําการแบงขอมูลทั้งหมดออกเปนสองสวนทุกครั้งที่มีการ เปรียบเทียบขอมูลทีต ่ องการคนหา (key) การคนหาเริ่มตนดวยการเปรียบเทียบ key กับขอมูล ณ ตําแหนงที่อยูกงึ่ กลางของ array ถา key มีคา นอยกวาขอมูล ณ ตําแหนงนี้การคนหาก็ยา ยไปคนทางซาย ของขอมูลนี้ และจะคนทางขวาถา key มีคามากกวาขอมูลทีต ่ ําแหนงนี้ การคนหาจะดําเนินไปจนกวาจะ คนพบ นั่นก็คือ key มีคาเทากับขอมูลที่ตาํ แหนงนั้น หรือไมก็ยุติการคนถาไมมีขอมูลนั้นใน array สิ่งทีส ่ ําคัญในการคนหาแบบนีก ้ ็คือ ขอมูลจะตองมีการจัดเก็บแบบจัดเรียงจากนอยไปหามาก เพราะถาไม อยูในรูปแบบนีแ ้ ลวการคนหาก็จะทําไมได วิธีการคนหาดวย binary search จะลดจํานวนครั้งของการเปรียบเทียบลงไปทีละครึ่ง ทําใหการคนหาใช เวลานอยลง ตัวอยางเชน การคนหาใน array ที่มีขอมูลเทากับ 1024 ตัวจะใชการเปรียบเทียบเพียง 10 ครั้ง ครั้งแรกลดลงเหลือ 512 ครั้งที่สองเหลือ 256 และครั้งตอ ๆ ไปเหลือ 128 64 32 16 8 4 2 และ 1 จะเห็นวาลดลงมาก ซึ่งเปนจุดแข็งของการคนหาของ binary search โปรแกรม BinSearch.java แสดง การคนหาดวยการใช binary search /* BinSearch.java */ import java.io.*; class BinSearch { public static void main(String[] args) { int[] list = {1, 2, 3, 4, 5, 6, 7, 8 ,9, 10}; //generate key to search int key = (int)(Math.random() * 10 + 1); int low = 0; //lower index int high = list.length - 1; //higher index int middle; //number at the middle (pivot) boolean found = false; //indicate search result

}

}

while(low <= high) { middle = (low + high) / 2; //calculate pivot if(key == list[middle]) { //if found - stop searching found = true; break; } else if(key < list[middle]) //key is in lower half high = middle - 1; else low = middle + 1; //key is in upper half } if(found) System.out.println("Found " + key + "!"); else System.out.println(key + " not found!");

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

109

โปรแกรม BinSearch.java ของเราเริ่มตนดวยการกําหนดให array list มีขอมูลเปนจํานวนเทากับ 10 ตัว และกําหนดใหขอมูลที่ตองการคนหา (key) มาจากการสุม หลังจากนั้นก็กาํ หนดให index หัว (low) และ ทาย (high) ของ array เปน 0 และ list.length – 1 ตามลําดับ เราจะใช while loop เปนตัวเขาหาขอมูล ใน array list ของเราดวยการเปรียบเทียบคาของ low กับ high ซึ่งถาเมื่อใดก็ตามที่คาของ low มากกวา หรือเทากับ high ก็หมายความวาการคนหาของเราไมประสพผลสําเร็จ คือไมมีขอมูลนั้นอยูใ น list เราก็จะ ยุติการทํางานทันที เราหาขอมูลที่อยูต  รงกลางดวย middle = (low + high) / 2; และเปรียบเทียบการคนหาที่ประสพผลสําเร็จดวยประโยค if(key == list[middle]) { found = true; break; } เราจะเปรียบเทียบและแบงขอมูลออกเปนสองสวนดวย else if(key < list[middle]) high = middle - 1; else low = middle + 1; เราจะยาย index ที่อยูห  ลังสุดใหเปน middle – 1 ถาขอมูลทีเ่ ปน key นอยกวาขอมูลที่อยู ณ ตําแหนง middle และจะยาย low ไปอยูที่ middle + 1 ถา key มีคามากกวาขอมูล ณ ตําแหนง middle เราจะทํา ไปจนกวาจะเจอขอมูลที่ตําแหนง middle หรือไมก็หยุดการทํางานโดยไมพบขอมูลที่ตองการคนหาเลย การเรียงลําดับ (sort) ขอมูลใน array มีวิธีการหลากหลายวิธีทส ี่ ามารถนํามาใชในการจัดเรียงขอมูลใน array แตเนื่องจากวาเรายังตองศึกษาถึง สวนประกอบอื่น ๆ ของ Java กอนที่เราจะนําเอาวิธีการเหลานั้นมาใชได ซึ่งหนังสือสวนมากก็จะนําเอา วิธีการจัดเรียงขอมูลไปไวในวิชาโครงสรางขอมูล (ซึ่งก็เปนหนังสือเลมตอไปจากหนังสือเลมนี้) ดังนั้นเรา จะพูดถึงเฉพาะการนําเอา method การ sort ที่ Java มีใหมาใชโดยตรงเพื่อใหการทํางานเปนไปได รวดเร็วยิ่งขึ้น เราเพียงแตสง array ที่เราตองการ sort ไปให method sort() ที่ Java มีให ดังนี้ Arrays.sort(list) โดยที่ list เปน array ที่เราตองการ sort โปรแกรม Sort.java แสดงวิธีการเรียกใช sort จาก class Arrays //Sort.java - recursive version import java.lang.Integer; import java.util.Arrays; class Sort { public static void main(String[] args) { int[] list = new int[100]; //array with 100 ints int i; //loop index //populate list with random ints for(i = 0; i < 100; i++) list[i] = (int)(Math.random() * 100 + 1);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

110

//display 100 ints to screen – 20 per line for(i = 0; i < list.length; i++) { if(i % 20 == 0) System.out.println(); System.out.print(list[i] + "\t"); } System.out.println(); Arrays.sort(list);

}

}

//calling sort from class Arrays

//display again for(int j =0 ; j < list.length; j++) { if(j % 20 == 0) System.out.println(); System.out.print(list[j] + "\t"); } System.out.println();

ยังมี method อีกหลายตัวใน class Arrays ที่เราสามารถเรียกใชได ทั้งนี้กต ็ องดูวาเรากําลังทําอะไรอยู ในที่นี้จะขอพูดอีกเพียง method เดียวคือ binarySearch() เพราะวาเราไดพูดถึงวิธีการเขียน code ของ binary search มากอนหนานีแ ้ ลว โปรแกรม BinarySearch.java แสดงถึงวิธีการเรียกใช method binarySearch() ที่วานี้ //BinarySearch.java - recursive version import java.util.Arrays; class BinarySearch { public static void main(String[] args) { int[] list = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int key = (int)(Math.random() * 10 + 1);//key to search for int found = Arrays.binarySearch(list, key);

}

}

if(found >= 0) System.out.println("Found " + key + " at index " + found); else System.out.println(key + " is not in the list!");

เราเรียก method binarySearch() ดวย parameter 2 ตัวคือ (1) array ที่มข ี อมูลอยู – ในที่นี้คือ list และ (2) ขอมูลที่ตองการคนหา – ซึ่งก็คือ key ในโปรแกรมดานบนนี้ ประโยค int found = Arrays.binarySearch(list, key) ถาขอมูลที่ตองการคนหาอยูใน list การเรียก method binarySearch() ก็จะไดคาของ index ที่ขอมูลนั้น อยูสงกลับมายังตัวแปร found แตถาหาไมเจอคาทีส ่ งกลับจะมีคานอยกวา 0 เสมอ ดังนั้นการแสดงผลจึง ตองเปรียบเทียบคาของ found กับคาของ 0 เมื่อทดลอง run ดูผลลัพธที่ไดคือ Found 3 at index 2 Found 1 at index 0

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

111

การสราง array ที่มข ี อมูลเปน array (Array of arrays) เราไดใช array ที่มีขอมูลเปน primitive type จากตัวอยางกอนหนานี้หลาย ๆ ตัวอยาง เรามาลองดูการ สราง array ทีม ่ ีขอมูลเปน array ดู เราจะเริม ่ ตนดวยการประกาศ ดังนี้ int[][] table = new int[5][5]; ซึ่งหมายถึงการประกาศใหตวั แปร table เปน array ที่มีขอมูล 5 ตัวโดยทีแ ่ ตละตัวนั้นเปน array ที่เก็บ ขอมูลที่เปน int อยู 5 ตัว เราจะใช [][] สองตัวเปนตัวบอกให Java รูวาตัวแปรตัวนี้คือ array ที่ใชเก็บ array โดยทัว่ ไปเรามักจะเรียก array ในลักษณะนี้วา array 2 มิติ ภาพที่ 4.2 แสดงถึงเนื้อที่ของ array table index ของขอมูลในแตละแถว

ชื่อของ array และ ตําแหนงของ ขอมูลแตละตัว (index) [0]

[1]

[2]

[3]

[4]

table[0]

table[1]

table[2]

table[3]

table[4]

int [] [] table = new int [5] [5]; ภาพที่ 4.2 การสราง array ที่เก็บ array (array 2 มิติ)

โปรแกรม Array9.java ที่เห็นดานลางนีแ ้ สดงการใช array 2 มิติ โดยกําหนดใหมีขนาด 5 x 5 และ กําหนดใหขอมูลมีคาอยูร ะหวาง 1 ถึง 10 ดวยการสุมจาก random() ความยาวหรือขนาดของ table หาไดจากคาคงที่ที่เก็บไว length เชนเดียวกันกับ array 1 มิติ สวนขนาด ของขอมูลที่อยูใ นแตละแถวหาไดจากคาคงที่ในแถวนั้น เชน table[0].length table[3].length โปรแกรม Array9.java ใช table[i].length เปนตัวกําหนดขนาดในแตละแถวโดยที่ i เปน index ของแถว นั้น ๆ /* Array9.java */ import java.io.*;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

112

class Array9 { public static void main(String[] args) { int[][] table = new int[5][5]; for(int i = 0; i < table.length; i++) { for(int j = 0; j < table[i].length; j++) table[i][j] = (int)(1 + Math.random() * 10); } for(int i = 0; i < table.length; i++) { for(int j = 0; j < table[i].length; j++) System.out.print(table[i][j] + "\t"); System.out.println(); } }

}

ผลลัพธของการ run โปรแกรม Array9.java คือ 7 5 7 7 10

3 8 6 10 4

2 5 8 9 4

8 4 6 7 2

7 8 2 5 2

เรามาดูโปรแกรมตัวอยางอีกตัวหนึ่งที่ประกาศและกําหนดคาใหกับ array 2 มิติดวยการกําหนดแบบ อัตโนมัติจาก Java เอง /* Array10.java */ import java.io.*; class Array10 { public static void main(String[] args) { //declare 2-D array with specific data int[][] table = { {1, 2, 3}, {5, 6, 8}, {7, 4, 6}, {4, 8, 9} }; for(int i =0 ; i < table.length; i++) { for(int j = 0; j < table[i].length; j++) System.out.print(table[i][j] + "\t"); System.out.println(); } }

}

เรากําหนดให table เปน array 2 มิติที่มจ ี ํานวนแถวเทากับ 4 และจํานวนขอมูลในแตละแถวเทากับ 3 โดยการกําหนดนั้นเราตองใสขอมูลในแตละแถวในเครื่องหมาย {} และแบงขอมูลที่อยูแถวในแตละแถว ดวยเครื่องหมาย , ดังนี้ int[][] table = { {1, 2, 3}, {5, 6, 8}, {7, 4, 6},

/* แถว 0 */ /* แถว 1 */ /* แถว 2 */

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

{4, 8, 9} };

113

/* แถว 3 */

เราสามารถทีจ ่ ะใหขอมูลอยูใ นบรรทัดเดียวกันได เชน int[][] table = {{1, 2, 3}, {5, 6, 8}, {7, 4, 6}, {4, 8, 9}}; หลังจาก run โปรแกรมแลว ผลลัพธที่ไดคือ 1 5 7 4

2 6 4 8

3 8 6 9

การใช array ที่มีจา ํ นวนของขอมูลในแตละแถวไมเทากัน เราสามารถทีจ ่ ะกําหนดใหขอมูลในแตละแถวของ array มีจํานวนไมเทากันได ดังตัวอยางดานลางนี้ double [][] list = new double[5][]; ซึ่งเปนการประกาศ array 2 มิติที่มจ ี ํานวนแถวเทากับ 5 แตจํานวนของขอมูลในแตละแถวยังไมไดถูก กําหนด เราอาจกําหนดใหขอมูลในแถว 0 มีจํานวนเทากับ 4 และขอมูลในแถว 4 มีจาํ นวนทากับ 10 เปน ตน ดังนี้ list[0] = new double[4]; list[4] = new double[10]; สวนขอมูลในแถวที่เหลืออยูกแ ็ ลวแตวาเราอยากที่จะใหมีขอ  มูลกี่ตัว หรือเราอาจกําหนดใหขอมูลในแตละ แถวมีจํานวนเทากับคาที่เพิ่มขึน ้ ตามคาของแถว (index) เชน int m = 0; while(m < 5) { list[m] = new double[m + 1]; m++; } โปรแกรม Array11.java สราง array 2 มิติทม ี่ ีขอมูลในแตละแถวเทากับคาของ index ในแถวนั้น ๆ /* Array11.java */ import java.io.*; class Array11 { public static void main(String[] args) { double [][]list = new double[5][]; //allocate space for each row int m = 0; while(m < 5) { list[m] = new double[m + 1]; m++; } for(int i = 0; i < list.length; i++) { for(int j = 0; j < list[i].length; j++) System.out.print(list[i][j] + "\t"); System.out.println();

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

}

}

การใช Array และ String

114

}

เมื่อ run ดูผลลัพธที่ไดคือ 0.0 0.0 0.0 0.0 0.0

0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0

การกําหนดขนาดของ array แบบนี้ทําใหการใชเนื้อที่ในการเก็บขอมูลในแตละแถวมีประสิทธิภาพมากขึ้น ทั้งนี้ก็เพราะวาเราใชเฉพาะเนื้อที่ทจ ี่ ําเปนตองใชเทานั้น ถาเราใชการกําหนดแบบเกาเราตองใช หนวยความจําเทากับ 8 x 25 = 200 byte แตถาเราใชการกําหนดตามเทาที่ใช เราก็จะใชหนวยความจํา เพียงแค 8 x 15 = 120 byte การสราง array ที่มีความจุของขอมูลในแตละแถวไมเทากันเอื้ออํานวยความสะดวกในการจองเนื้อที่ ทํา ใหการใชหนวยความจํามีประสิทธิภาพมากยิ่งขึ้น แตการทํางานจะตองมีการระมัดระวังเปนพิเศษ เพราะ จํานวนของขอมูลในแตละแถวมีจํานวนไมทา กัน ผูอานตองใชความละเอียดในการออกแบบ ถาตองการใช array แบบนี้ ตัวอยางการใช Array of arrays ในการหาคา max คา min และคาเฉลีย ่ //ArrayOfArrays.java import java.io.*; class ArrayOfArrays { public static void main(String[] args) { //inititial scores int [][]score = { {45, 87, 68, 57}, {98, 70, 58, 69}, {85, 42, 68, 82} }; double average; //average of scores int max, min, total = 0; //maximum, minimum, total of scores int count = 0; //total scores max = score[0][0]; //assuming max score is at [0][0] min = score[0][0]; //assuming min score is at [0][0] //looping for 3 rows for(int i = 0; i < score.length; i++) { //looping for 4 columns for(int j = 0; j < score[i].length; j++) { if(score[i][j] > max) //find max score max = score[i][j]; if(score[i][j] < min) //find mim score min = score[i][j]; total += score[i][j]; //calculate total count++; //number of scores } } //calculate average of scores average = (double)total / count; System.out.println("Maximum score is " + max); System.out.println("Minimun score is " + min); System.out.println("Average score is " + average);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

}

การใช Array และ String

115

}

โปรแกรม ArrayOfArrays.java กําหนดให score เปน array ที่เก็บขอมูลเปนจํานวนเทากับ 3 แถว แถว ละ 4 ตัว เราจะหา score ที่เล็กที่สด ุ score ที่ใหญทส ี่ ด ุ รวมไปถึงการคํานวณหาคาเฉลี่ยของ score ทั้งหมด เราใช for – loop 2 ตัวในการเขาหา array ของเราเหมือนเดิม พรอมทั้งตรวจสอบวา score ตัว ไหนเปน max และ score ตัวไหนเปน min ดวยการกําหนดใหทั้งสองตัวแปรมีคา เปนขอมูลตัวแรกสุดที่ อยูใน array และจะทําการเปรียบเทียบขอมูล ณ ตําแหนงทั้งหมดใน array กับขอมูลนี้ ประโยค if(score[i][j] > max) max = score[i][j]; จะเปลี่ยนคาของ max ใหมีคาเทากับ score[i][j] ถาขอมูลทีต ่ ําแหนงนีม ้ ากกวาคาของ max และประโยค if(score[i][j] < min) min = score[i][j]; จะเปลี่ยนคาของ min ใหมีคาเทากับ score[i][j] ถาขอมูลทีต ่ ําแหนงนี้นอยกวาคาของ min วิธีการหาคา ของ max และ min แบบนี้สามารถนําไปใชไดกับการหาคา max และ min โดยทั่วไปไดโดยไมตองสนใจ วาขอมูลที่อยูภายใน array จะมี range อยูชวงไหน ทั้งนี้เพราะเราใชขอมูลตัวแรกสุดเปนตัวตรวจสอบ กอน ทําใหการหาคาของทั้ง max และ min เปนไปไดโดยไมตองกําหนดคาใหกับตัวแปร max หรือ min ใด ๆ ทั้งสิ้น (ถาเราไมตองการตรวจสอบเอง เราก็สามารถทีจ ่ ะเรียกใช method max() และ min() ที่มีอยู ใน class Math ได – ดูในบทกอน ๆ) ในสวนของการหาคาเฉลี่ยก็เหมือนกับที่เราไดเคยทํามาแลวกอน หนานี้ การใช array of arrays นั้นก็เหมือนกับที่เราใชตาราง หรือ table ในการเก็บขอมูลตาง ๆ หนังสือหลาย ๆ เลมเรียก array of arrays ที่มแ ี ค row และ column วา array 2 มิติ (two dimensional array) สวน array of arrays ที่มีขอมูลเปน array อีกเราก็มักจะเรียกวา array 3 มิติ เปนดังนี้ทุกครั้งที่มก ี ารเพิ่มมิติ ใหกับ array แตการมองเห็นหรือการใชก็คงมีนอย ถาหากวาจํานวนมิตท ิ ี่ใชมีมากกวา 3 มิติ เพราะวา คนเราชินกับการมองเห็นแบบ 3 มิติตลอดเวลา (เราจะทิ้งใหผูอานศึกษาในเรื่องของ array 3 มิติเอง) การใช String การใช string นั้นสามารถทําไดหลาย ๆ วิธี และวิธีแรกที่เราจะทําความรูจักนั้นเปนการใช array เปนหลัก ในการทํางานกับ string นั้น ๆ เราคงไมสามารถทีจ ่ ะเรียก string ในลักษณะนี้ไดเต็มปากเต็มคํามากนัก เพราะวาโดยความเปนจริงแลว array ที่เราใชในการทํางานที่เกี่ยวของกับ String นั้นไมใช string โดยตรงแตเปน array ที่เก็บ char หลาย ๆ ตัวไว หรือที่เรียกกันวา array of characters ซึง่ หนังสือ หลาย ๆ เลมก็มักจะเรียก string วา array of characters เราจะตรวจสอบวิธีการใช string แบบนี้พอ สังเขป แลวเราจะกลับมาพูดถึง String ของ Java อยางละเอียดอีกทีหนึ่ง Array of characters การประกาศ string แบบนี้ทําไดงาย ๆ เหมือนกับที่เราประกาศใช array ที่เก็บขอมูลชนิดอืน ่ เพียงแตเรา เปลี่ยนให array เก็บ char แทนเทานั้น เชน char [] string = new char[20]; การประกาศดานบนนี้เปนการสราง array ที่ใชเก็บ char จํานวนเทากับ 20 ตัว โปรแกรมตัวอยางดานลาง แสดงการใช array of characters //ArrayOfChars.java import java.io.*; class ArrayOfChars { public static void main(String[] args) {

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

116

//declare array of char char[] str = new char[26]; int i = 0;

}

}

//populate str with characters a to z for(char c = 'a'; c <= 'z'; c++) { str[i] = c; i++; } //print all characters to screen for(i = 0; i < 26; i++) System.out.print(str[i]); System.out.println();

โปรแกรม ArrayOfChars.java เริ่มตนดวยการสราง array of chars จํานวน 27 ตัวจากประโยค char[] str = new char[26]; หลังจากนั้นก็ใช for – loop ในการกําหนดคาใหกับทุก ๆ ตําแหนงของ str ดวยการใช char เปน index ของ loop เนื่องจากวาการเพิม ่ คาใหกับ char นั้นที่จริงแลวเปนการเพิ่มคาใหกับตัวเลขที่เปนตัวแทนของ ตัวอักษรนั้น ๆ เชน ถาเรากําหนดให char c = 'f' การเพิ่มคาใหกับ c หนึ่งครั้งจะทําให c มีคาเปน 'g' ซึ่ง เปนตัวอักษรทีอ ่ ยูถัดไปในตาราง ASCII เพราะฉะนั้นการใช for – loop นี้ก็ทําใหเกิดการกําหนดคาใหกับ str ทุกตําแหนง for(char c = 'a'; c <= 'z'; c++) { str[i] = c; i++; } ผูอานคงเดาไดวาผลลัพธของโปรแกรมตัวนี้คอ ื อะไร Æ abcdefghijklmnopqrstuvwxyz การใช array of characters นั้นไมคอยจะสะดวกมากนัก ทั้งนี้เพราะเปนการทํางานที่เกี่ยวกับ array เรา อยากที่จะมี string จริง ๆ ที่เราสามารถที่จะทํากระบวนการตาง ๆ ได เชน บวก string 2 ตัวเขาดวยกัน หรือตรวจสอบความเทากัน ความเหมือนกันของ string อยางนี้เปนตน และ Java ก็มี class String ใหเรา เรียกใชงานที่เกี่ยวของกับ string โดยตรง String ใน Java String ใน Java นั้นเปน object ดังนั้นเราจึงจําเปนตองเรียกใช class String ในการสราง string เพื่อการ ใชงานของเรา เชน เราอาจตองการเก็บชื่อของ user ไวในโปรแกรม หรือสงขอความที่เปน string ไปให user อยางนี้เปนตน การประกาศใช String ก็ไมยาก ซึ่งทําไดดังนี้ String str = new String("Java is fun"); หรือแบบนี้ String str = "Java is fun"; โดยเฉพาะการประกาศในประโยคที่สองนี้ มีผลเทากับประโยค 2 ประโยคตอไปนี้ char[] str = {'J', 'a', 'v', 'a', ' ', 'i', 's', ' ', 'f', 'u', 'n'}; String str = new String(str);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

117

จะเห็นไดวา string ก็คือ array of chars นั่นเอง บางครั้งการประกาศตัวแปร string โดยทีไ ่ มมีการ กําหนดคาใหกบ ั string นั้นเราก็ทําไดดวยการประกาศเหมือนกับการประกาศตัวแปรชนิดอื่น เชน String name; ซึ่งมีความหมายวาตัวแปร name เปน string ที่ไมไดอางถึงคาใด ๆ เลย และถาเรา compile โปรแกรมที่ มีการประกาศแบบนี้จะมี error เกิดขึ้น วิธีการแกไขเพื่อไมให Java ฟองตอน compile เราตองกําหนดคา null ใหกับ string name ดังนี้ String name = null; ซึ่งบอกให Java รูวา string name ไมไดอางถึงขอมูลใด ๆ เลย เราสามารถที่จะอางถึงขอมูลใด ๆ ก็ได หลังจากนั้น ลองมาดูโปรแกรมตัวอยางการทํางานกับ string //StringOps.java import java.io.*; class StringOps { public static void main(String[] args) { String first = "Java "; String second = "Programming"; String third = null; int percent = 100;

}

}

third = first + second; System.out.println(third + " is " + percent + "% fun!");

โปรแกรม StringOps.java ประกาศตัวแปรที่เปน String 3 ตัวคือ first second และ third โดยกําหนดให first มีคาเปน "Java " second มีคาเปน "Programming" และ third ไมมีคาอางอิงถึง string ใด ๆ พรอม กันนี้เราไดกําหนดใหตัวแปร percent มีคาเปน 100 ประโยค third = first + second; ทําการรวม first และ second เขาดวยกัน ซึ่งทําให third มีคาเปน "Java Programming" และในประโยค ที่ทาํ การแสดงผลไปหนาจอนัน ้ เราไดเพิ่มการแสดงผลคาของตัวแปร percent และ string คงทีต ่ ัวอื่นเขา ไปดวยเพื่อใหผลลัพธเปน Java Programming is 100% fun! เราสามารถทีจ ่ ะรวมคาของตัวแปรอื่นที่ไมใช string เขากับ string ไดดังนี้ สมมติวาเราเพิม ่ ตัวแปรตอไปนี้ int percent = 100; String is = " is "; String fun = "%fun!"; และเรารวม String และ int เขาดวยกัน ดวยประโยค third = first + second + is + percent + fun;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

118

เราก็จะไดผลลัพธเหมือนกันกับที่เราไดทํากอนหนานี้ สาเหตุที่ทาํ ไดเพราะ Java จะเปลี่ยน int ใหเปน string กอนที่จะรวมเอา string ทั้งหมดเขาดวยกัน การเปรียบเทียบ String เราไมสามารถที่จะเปรียบเทียบ string 2 ตัวดวยการใช == ไดเหมือนกับที่เราทํากับตัวแปรที่เปน primitive type ได เชน first == third เพราะวาประโยคดังกลาวจะเปรียบเทียบวา string ทั้งสองตัวอางถึงที่เดียวกันหรือไม (ทีท ่ ี่เก็บ string ใด string หนึ่ง) เชน ถาเรามี String myString = "Motorcycle"; String yourString = myString; ซึ่งทําใหตวั แปร myString และ yourString อางถึงขอมูลเดียวกัน (และจะใหคา true ถามีการ เปรียบเทียบดวย ==) ไมใชการเปรียบเทียบถึงขอมูลทีต ่ ัวแปรทั้งสองอางอยู เชนถาเรามี string ตอไปนี้ String keyboard = "from Thailand"; String kb = "from Thailand"; ถาเราเปรียบเทียบดวยการใช if(keyboard == kb) … เราจะไดคา false ถึงแมวาตัวแปรทั้งสองจะมีคาที่เหมือนกัน ทั้งนี้เพราะวาเครื่องหมาย == จะ เปรียบเทียบคาอางอิง (ที่อยู หรือ address ในหนวยความจํา) ของตัวแปรทั้งสองไมใชคา ทีท ่ ั้งสองตัว แปรเก็บไว เราตองใช method อื่นที่ Java มีใหใน class String โปรแกรมตัวอยางของการเปรียบเทียบ string //StringCompare.java import java.io.*; class StringCompare { public static void main(String[] args) { String first = "Java "; String second = "Programming"; String third = "Java Programming"; String forth; forth = first + second; //forth is "Java Programming" if(third == forth) System.out.println("third and forth refer to the same string"); else System.out.println("third and forth do not refer to the same string"); first = forth; //first and forth refer to the same string System.out.println("first is " + first); System.out.println("forth is " + forth); if(first == forth) System.out.println("first == forth is true"); else

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

}

}

การใช Array และ String

119

System.out.println("first == forth is false");

โปรแกรม StringCompare.java แสดงถึงการเปรียบเทียบ string ดวยการใชเครื่องหมาย == ถาเรา สังเกตใหดีจะเห็นวา string third และ forth มีคาที่เหมือนกัน (string ที่ประกอบไปดวย char ที่ เหมือนกันหมด) เมื่อ run ดูผลลัพธที่ไดคือ third and forth do not refer to the same string ซึ่งบอกใหเรารูว าการใชเครื่องหมาย == เปรียบเทียบความเหมือนหรือความแตกตางของ string ไมได เชนเดียวกันกับประโยคเปรียบเทียบถัดมาในโปรแกรม เรากําหนดให first อางถึงขอมูลที่เดียวกันกับ forth และเมื่อเรา run ผลลัพธที่ไดก็เหมือนกับที่เราไดคาดหวังไวคือ first is Java Programming forth is Java Programming first == forth is true ถาเราตองการที่จะเปรียบเทียบ string จริง ๆ เราตองใช method equals() และ method compareTo() ดังโปรแกรมตัวอยางตอไปนี้ //StringCompare1.java import java.io.*; class StringCompare1 { public static void main(String[] args) { String first = "Java "; String second = "Programming"; String third = "Java ProgramminG"; String forth; forth = first + second; //forth is "Java Programming" if(third.equals(forth)) System.out.println("third equals forth"); else System.out.println("third not equals forth");

}

}

first = forth; //first and forth refer to the same string if(first.equals(forth)) System.out.println("first equals forth"); else System.out.println("first not equals forth");

เราไดเปลี่ยนให third มีคาเปน "Java ProgramminG" เพื่อที่จะแสดงใหเห็นวาในการเปรียบเทียบนั้น char ทุกตัวจะตองเหมือนกัน ผลลัพธที่เราไดจากการ run คือ third not equals forth first equals forth เราใชประโยค third.equals(forth) ในการเปรียบ third และ forth วามีคาทีเ่ หมือนกัน (เทากัน) ซึ่งถา เทากันจริงผลลัพธที่ไดจากการเปรียบจะมีคา เปน true และจะใหคา false ถาไมเทากัน การเปรียบเทียบ string 2 ตัวเพื่อตรวจสอบความเทากันนั้นเราจะเอาตัวไหนอยูดานหนาก็ได เชน

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

120

third.equals(forth) หรือ forth.equals(third) ก็ได method equals() จะตรวจสอบตัวอักษรทุกตัวที่อยูใ น string โดยใหความสนใจในเรื่องของตัวอักษรวา เปนตัวอักษรตัวเล็กหรือตัวใหญ การตรวจสอบจะใหคาที่เปนจริงถาเหมือนกันทั้งรูปรางและขนาด เชน g หรือ G ไมใชตวั อักษรตัวเดียวกัน การตรวจสอบจะเปน false ในการเปรียบเทียบบางครั้งเราก็ไมสนใจวาตัวอักษรที่อยูภ  ายใน string นั้นเปนตัวเล็กหรือตัวใหญ ซึ่งถา เราตองการเพียงแตตรวจสอบถึงความเหมือนทางรูปรางเราก็ตองใช method equalsIgnoreCase() ใน การเปรียบเทียบ string นั้น ๆ ถาเราเปลีย ่ นการเปรียบเทียบในโปรแกรมตัวอยางกอนหนานี้จากการใช equals() มาเปน equalsIgnoreCase() ดังนี้ if(third.equalsIgnoreCase(forth)) System.out.println("third equals forth"); else System.out.println("thrid not equals forth"); เราก็จะไดผลลัพธเปน third equals forth การเปรียบเทียบความไมเทากัน (มากกวา หรือ นอยกวา) ของ string หลาย ๆ ครั้งเราตองตรวจสอบถึงความมากกวา หรือ นอยกวาของ string เพื่อใหการจัดเก็บ string นั้น ๆ อยูในรูปแบบทีม ่ ีการจัดเรียง ไมวาจะเปนจากนอยไปหามาก หรือมากไปหานอย ในการตรวจสอบวา string ตัวไหนมากกวาหรือนอยกวากันนั้น เราจะใช method compareTo() เชน myString.compareTo(yourString); สมมติวา myString มีคาเปน "lovely bike" และ yourString มีคาเปน "lovely kite" การเปรียบเทียบดวย compareTo() จะใหคาที่เปนบวก ทั้งนี้ก็เพราะวา ตัวอักษร 'k' ใน yourString นั้นมีคามากกวาตัวอักษร 'b' ใน myString เรามาดูโปรแกรมตัวอยางการใช method compareTo() กันดีกวา //StringCompareTo.java import java.io.*; class StringCompareTo { public static void main(String[] args) { String first = "lovely bike"; String second = "lovely kite"; String third = "lovely"; //compare first and second if(first.compareTo(second) > 0) System.out.println("first is greater than second"); else System.out.println("second is greater than first"); //compare first and third if(first.compareTo(third) > 0) System.out.println("first is greater than third"); else System.out.println("third is greater than first"); String a = "A";

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

121

String z = "Z"; String str1 = "AAA"; String str2 = "AAA"; //compare a and z if(a.compareTo(z) < 0) System.out.println(a + " is less than " + z);

}

}

//compare str1 and str2 if(str1.compareTo(str2) == 0) System.out.println(str1 + " equals " + str2);

ผลลัพธที่เราไดจากการ run คือ second is greater than first first is greater than third A is less than Z AAA equals AAA โปรแกรมของเราเปรียบเทียบ first กับ second ดวยการตรวจสอบคาที่ไดจากการเปรียบเทียบกับ 0 ซึ่งถา first มากกวา second ประโยคนี้ก็จะเปน true แตเนื่องจากวา first นั้นไมมากกวา second การ เปรียบเทียบของเราจึงใหผลลัพธเปน false Java จึงประมวลผลประโยคที่อยูใน else (สงผลลัพธไป หนาจอ) – การประมวลผลประโยคอื่น ๆ ก็คลายกัน โดยทั่วไปเราจะเปรียบเทียบคาที่ไดจาก method compareTo() กับ 0 เสมอเพราะจะทําใหเราไดคา true หรือ false ที่สามารถนําไปใชในการเลือกประมวลผลประโยคตาง ๆ ไดตามที่เราตองการ การเปรียบเทียบความเหมือนและเทากันก็ทาํ ไดดวยการใชเครื่องหมาย == ดังเชนประโยคสุดทายของ โปรแกรม if(str1.compareTo(str2) == 0) System.out.println(str1 + " equals " + str2); ในการเปรียบเทียบดวย method compareTo() นี้คาทีส ่ งกลับมาเปนไปไดเพียงแค 3 คา คือ -1, 0, และ 1 เทานั้น โดยที่ -1 หมายถึง string ที่อยูทางซาย นอยกวา string ที่อยูทางขวา (string ที่เปน parameter) 0 หมายถึง string ทั้งสองนั้นเทากัน 1 หมายถึง string ที่อยูท  างซาย มากกวา string ที่อยูทางขวา เชน ถาเรามีประโยค string1.compareTo(string2); string1 หมายถึง string ที่อยูท  างซาย string2 หมายถึง string ที่อยูท  างขวา หรือ string ที่เปน parameter การเขาหาตัวอักษรทีอ ่ ยูใน string เราสามารถทีจ ่ ะเขาหาตัวอักษรตาง ๆ ที่อยูใน string ไดดวยการใช method ตาง ๆ ดังที่ไดแสดงไวเปน ตัวอยางในโปรแกรม StringChars.java //StringChars.java import java.io.*;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

122

import java.lang.Character; class StringChars { public static void main(String[] args) { //setting up constant string String string = "Learn to write programs in Java doesn't take" + " as long as I think it would. But to fully understand" + " it is a time consuming task."; int int int int int

charCount = 0; vowelCount = 0; lowerCaseCount = 0; upperCaseCount = 0; spaceCount = 0;

//count //count //count //count //count

of of of of of

letters vowels lowercase letters uppercase letters white spaces

//check all letters for(int i = 0; i < string.length(); i++) { char ch = string.charAt(i); //check if it's a letter if(Character.isLetter(ch)) charCount++; //check if it's an uppercase if(Character.isUpperCase(ch)) upperCaseCount++; //check if it's a lowercase if(Character.isLowerCase(ch)) lowerCaseCount++; //check if it's a white space if(Character.isWhitespace(ch)) spaceCount++;

}

}

}

//convert it to lowercase ch = Character.toLowerCase(ch); //check if it's a vowel if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') vowelCount++;

System.out.println(charCount + " characters counted."); System.out.println(upperCaseCount + " uppercase letters counted."); System.out.println(lowerCaseCount + " lowercase letters counted."); System.out.println(vowelCount + " vowels counted."); System.out.println(charCount - vowelCount + " consonants counted."); System.out.println(spaceCount + " spaces counted.");

ผลลัพธที่ไดจากการ run คือ 99 characters counted. 4 uppercase letters counted. 95 lowercase letters counted. 37 vowels counted. 62 consonants counted.

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

123

24 spaces counted. การทํางานของโปรแกรมเริม ่ ตนดวยการกําหนดใหตัวแปร string มีคาเปนคาคงที่ที่อยูใน " " เราจะเขาหา ตัวอักษรแตละตัวดวย for – loop และดึงเอาตัวอักษรออกมาจาก string แตละตัวดวยคําสั่ง char ch = string.charAt(i) ซึ่งจะดึงเอาตัวอักษร ณ ตําแหนง index i นั้น ๆ มาเก็บไวที่ตัวแปร ch หลังจากนั้นก็ตรวจสอบดวย method ตาง ๆ ที่มีอยูใน class Character เชน Character.isLetter(ch) Character.isUpperCase(ch) Character.isLowerCase(ch) Character.isWhitespace(ch)

ใหคา ใหคา ใหคา ใหคา

true true true true

ถาเปนตัวอักษร ถาเปนตัวอักษรตัวใหญ ถาเปนตัวอักษรตัวเล็ก ถาเปนชองวาง (เคาะแปน หรือ tab)

พรอมทั้งเพิ่มคาใหกับตัวแปรทั้งหลายที่เปนที่เก็บจํานวนครัง้ ของตัวอักษรตาง ๆ ที่ปรากฏใน string หลังจากนั้นก็เปลี่ยนตัวอักษรใหเปนตัวเล็กเพื่อใชตรวจสอบวาเปนสระในภาษาอังกฤษหรือไม สาเหตุที่ เปลี่ยนเพราะเราไมอยากที่จะเสียเวลาในการตรวจสอบสระตัวเล็กทีหนึ่ง และตัวใหญอีกทีหนึ่ง อยางไรก็ ตามทั้งสองก็เปนสระอยูเสมอ ch = Character.toLowerCase(ch); if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') vowelCount++; ยังมี method อีกมากมายใน class Character และ class String ที่เราสามารถนํามาใชในการทํางานที่ เกี่ยวของกับ string ตัวอยางตอไปนี้เปนการคนหาคํา (sub string) ที่อยูใ น string ดวยการใช method indexOf() //IndexOf.java import java.io.*; import java.lang.Character; class IndexOf { public static void main(String[] args) { //setting up constant string String string = "Learn to write programs in Java doesn't take" + " as long as I think it would. But to fully understand" + " it is a time consuming task."; int itCount = 0; //count of it String it = "it"; //string to seach for //search for "it" int index = string.indexOf(it); while(index >= 0) { itCount++; //move to first letter after last "it" index += it.length(); //look for next "it" index = string.indexOf(it, index); }

}

}

System.out.println("it appeared " + itCount + " times.");

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

124

ผลลัพธของโปรแกรมคือ it appeared 3 times. โปรแกรมของเรากําหนดให index มีคาเปนตําแหนงที่ "it" ปรากฏอยูใ น string ดวยคําสั่ง int index = string.indexOf(it) เมื่อการคนหาประสพผลสําเร็จเราก็จะใช while – loop ในการคนหาตอไป แตกอนที่เราจะดําเนินการนั้น เราจะเพิ่มคาหนึ่งคาใหกับ itCount กอน หลังจากนั้นเราจะเลื่อน index ไปอยูในตําแหนงของตัวอักษรตัว แรกที่อยูหลัง "it" ดวยคําสั่ง index += it.length() เนื่องจากวา method indexOf() จะสงคาของ ตําแหนงของตัวอักษรตัวแรกของ "it" มาให เสร็จแลวก็ทาํ การคนหาตอไปดวยคําสั่ง index = string.indexOf(it, index) ทําการคนหาไปจนกระทั่งหมด string เราก็ออกจาก while – loop ในการใช indexOf() คนหานัน ้ เราตองเปรียบเทียบคาทีส ่ งกลับมากับ 0 เพราะถาหาไมเจอคาของ index ก็จะเปน -1 ทําใหเราหลุดออกจาก while – loop ได Method indexOf() นั้นมีอยูส  องตัวทีร่ ับเงื่อนไข (parameter) ไมเหมือนกัน ดังที่เห็นในโปรแกรม ตัวแรก รับเพียงคาเดียวคือ sub string ที่ตองการคนหา สวนตัวที่สองรับคาสองคาคือ sub string ที่ตองการ คนหา และ จุด (index) เริ่มตนของการคนหา ซึ่งถาสังเกตใหดีเราใช indexOf() ตัวแรกในการคนหาครั้ง แรก และตัวทีส ่ องในการคนหาตัวตอ ๆ ไป ทั้งนี้ก็เพราะวาครั้งแรกสุดเราไมรูวา คาของ index แตในครั้งที่ สองนั้นเราไดคา ของ index แลว ผูอานตองจําไวเสมอวา indexOf() จะสงคา -1 มาใหถา ไมมี sub string ใน string นั้น ๆและจะสงคาของ ตําแหนงที่ sub string นั้นอยูถามี sub string ที่วา ตอไปเราลองมาดูโปรแกรมทีท ่ ําการดึงเอากลุมของตัวอักษร (คํา) หรือที่เรียกวา sub string ออกจาก string ดู //SubString.java import java.io.*; import java.lang.Character; class SubString { public static void main(String[] args) { //setting up constant string String string = "Learning Java"; String str1 = string.substring(0); String str2 = string.substring(9); String str3 = string.substring(0, 8);

}

}

//the whole string //string: "Java" //string: "Learning"

System.out.println("str1 > " + str1); System.out.println("str2 > " + str2); System.out.println("str3 > " + str3);

Java มี method substring() ใหเราใชอยูส  องตัว คือ substring() ที่ไมมี parameter และ substring() ที่มี parameter อยูสองตัว โดยทีต ่ ัวแรกเปน index เริ่มตนของ sub string และ parameter ตัวทีส ่ อง เปน index ตัวสุดทายที่อยูใน sub string นั้นแตไมนับตัวมันเอง ดังที่ไดแสดงไวในโปรแกรม

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

125

String str2 = string.substring(9) หมายความถึงการเริ่มนับที่ index = 9 ไปจนถึงตัวสุดทายใน string นั้น คือ เริ่มที่ตัวอักษร 'J' ไปจบที่ ตัวอักษร 'a' ซึ่งคือคําวา "Java" สวน String str3 = string.substring(0, 8) หมายถึงการเริม ่ นับที่ index = 0 ไปจนถึงตัวที่ 8 คือตั้งแตตัวอักษร 'L' ไปจนถึงตัวอักษร ' ' (space) แต ไมนับ space ดังนั้น sub string ที่เราไดก็คือ "Learning" เราสามารถทีจ ่ ะดึงเอา sub string ออกจาก string ที่เปนคาคงที่ได เชน String sub = "Basic idea about Java".substring(6) จะให "idea about Java" หรือ String sub = "Basic idea about Java".substring(6, 10) จะให "idea" ตารางที่ 4.1 แสดงถึง method ตาง ๆ ของ class String ตาราง 4.1 method ของ class String method length() indexOf(String) indexof(String, start index) lastIndexof(String) lastIndexof(String, start index) trim() substring(start index) substring(start index, end index) replace(old char, new char) charAt(index) equals(String) equalsIgnoreCase(String) startsWith(String) startsWith(String, start index) endsWith(String)

ความหมาย ความยาวของ String (จํานวนตัวอักษร) ตําแหนงเริ่มตนที่ String ตัวนี้อยู ถาไมมีจะเปน -1 ตําแหนงเริ่มตนที่ String ตัวนี้อยูตามจุดที่กําหนด ถาไม มีจะเปน -1 ตําแหนงสุดทายของ String ตัวนี้ เทากับ -1 ถาไมมี ตําแหนงสุดทายของ String ตัวนี้ตามจุดที่กําหนด เทากับ -1 ถาไมมี String ที่ไมมี space อยูทั้งดานหนา และหลัง คาของ String ณ ตําแหนงที่กาํ หนดจนจบ คาของ String ณ ตําแหนงที่กาํ หนดทั้งสอง เปลี่ยน char ทุกตัวดวย char ตัวใหมที่กําหนด คาตัวอักษร ณ ตําแหนงที่กําหนด true ถา String ทั้งสองตัวเทากัน true ถา String ทั้งสองตัวเทากัน ไมสนใจ case true ถา String เริ่มตนดวย String ที่กําหนด true ถา String เริ่มตนดวย String ที่กําหนด ณ ตําแหนงที่กําหนด true ถา String จบดวย String ที่กําหนด

การใช class StringBuffer ในการสราง string แทนที่จะใช class String เราก็สามารถที่จะใช class StringBuffer แทนได การทํางานก็ไมแตกตางกัน มากมายนัก เชน สมมติวาเราจะสราง string สักตัวหนึ่งเราก็ทําได ดังนี้ StringBuffer string = new StringBuffer("Basic String Operations"); เราสราง object หนึ่งตัวชื่อ string จาก class StringBuffer โดยกําหนดคาเบื้องตนเปน "Basic String Operations" เราไมสามารถทีจ ่ ะสราง string เหมือนกับที่เราสรางดวย class String ได เราตองจองเนื้อที่ ใหกับตัวแปรดวยคําสั่ง new กอน หลังจากนัน ้ ก็กําหนดคาใหกับตัวแปรนี้ เราอาจประกาศดวยการประกาศ แบบนี้

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

126

StringBuffer string = null; string = new StringBuffer("Just another way to declare"); แตไมใชแบบนี้ StringBuffer string = "Just another way to declare"; ขอดีของการใช StringBuffer ก็คือ เราสามารถทีจ ่ ะเปลี่ยนแปลง string ที่เราสรางขึ้นได (object จาก class String ทีเ่ ราใชกอนหนานี้ทําไมได) และเรายังสามารถที่จะกําหนดขนาดของ string จาก class StringBuffer ไดตามความพึงพอใจของเรา ลองมาดูโปรแกรมตัวอยางการใช object จาก class StringBuffer กัน //StringBufferTest.java import java.io.*; class StringBufferTest { public static void main(String[] args) { //setting up constant string StringBuffer string = new StringBuffer("fish"); System.out.println("string is " + string); //append "er" after "fish" string.append("er"); System.out.println("string is " + string);

}

}

//append "man" after "fisher" using method insert() string.insert(string.length(), "man"); System.out.println("string is " + string);

โปรแกรม StringBufferTest.java แสดงการสราง object จาก class StringBuffer ดวยคําสั่ง StringBuffer string = new StringBuffer("fish") จะทําใหคาของ string เปน f i uiui

s

h

หลังจากที่เราแสดงขอมูลที่อยูใ น string แลวเราก็นําเอา string "er" มาเชื่อมเขากับ string "fish" ดวย คําสั่ง string.append("er") จะทําใหคาของ string เปน f

i

s

h

e

r

ทําใหขอความที่อยูใน string เปลี่ยนเปน "fisher" และหลังจากที่เราแสดงผลที่ไดใหมนี้ไปยังหนาจอ เรา ก็เปลี่ยนขอมูลใน string ใหมดวยการนําเอา string "man" มาเชื่อมเขากับ string ที่เราไดกอนหนานี้ดวย การใช method insert() ดังนี้ string.insert(string.length(), "man")

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

127

จะทําใหคาของ string เปน f

i

s

h

e

r

m

a

n

เราเรียก insert() ดวย parameter 2 ตัวคือ 1). ความยาวของ string เดิมซึง่ ก็คือจุดเริ่มตนของการเชื่อม และ 2). string ตัวใหมที่เราตองการเชื่อม คือ "man" เมื่อ run ดูแลวผลลัพธที่ไดคือ string is fish string is fisher string is fisherman เราสามารถทีจ ่ ะเปลี่ยนขนาดของ object ที่มาจาก class StringBuffer ไดดังนี้ string.setLength(6) ซึ่งจะทําใหขอมูลที่อยูใ น string เปลี่ยนไป หลังจากที่เราเปลี่ยนขนาดของ string และเพิ่มประโยค สําหรับการแสดงผลในโปรแกรมของเราใหเปน System.out.println("string after set length is " + string) ผลลัพธที่เราจะไดจากการ run ก็จะกลายเปน string after set length is fisher เราไมไดถูกจํากัดใหใสขอมูลที่เปน string เทานั้นใน object ที่มาจาก class StringBuffer เราสามารถที่ จะเรียกใช append() หรือ insert() กับขอมูลชนิดอื่น ๆ ได เชนโปรแกรมตัวอยางตอไปนี้ //StringBufferTest1.java import java.io.*; class StringBufferTest1 { public static void main(String[] args) { //setting up constant string StringBuffer string = new StringBuffer(); string.append(2); System.out.println("string is " + string); //append " fisher" after 2 string.append(" fisher"); System.out.println("string is " + string); //append "men" after "fisher" using method insert() string.insert(string.length(), "men"); System.out.println("string is " + string); string.append(" with "); System.out.println("string is " + string);

}

}

string.append(100); string.append(" fish."); System.out.println("string is " + string);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

128

เราไมไดทําอะไรมากมายนักเพียงแตเรียกใช method append() ดวยคาที่เปน int เชน string.append(2) หรือ string.append(100) เปนตน Java ยังยอมใหเราเชื่อมขอมูลที่มค ี วาม หลากหลายของชนิดของขอมูลเขาสู object ที่มาจาก class StringBuffer ไดโดยไมจาํ กัดจํานวน ผลลัพธของโปรแกรมหลังจากการปรับปรุงคือ string string string string string

is is is is is

2 2 2 2 2

fisher fishermen fishermen with fishermen with 100 fish.

สวนหนึ่งของ class StringBuffer ที่นาสนใจก็คือ การกําหนดขนาดใหกับ buffer ที่รองรับขอมูลใน object ตาง ๆ ที่เกิดจาก class นี้ นั่นก็คือ Java จะกําหนดขนาดของ buffer ใหเทากับขอมูลที่มีอยูใน buffer บวกกับอีก 16 ตัวอักษรเสมอ เชน ถาเราสราง object StringBuffer name = new StringBuffer("Chiang Mai"); ซึ่งมีจํานวนตัวอักษรทั้งหมด (นับชองวางดวย) เทากับ 10 ตัว Java จะจองเนื้อที่ใหมีความจุเทากับ 26 ตัว เราสามารถตรวจสอบความจุของ buffer ดวยการเรียกใช method capacity() ได เชน ถาเราสราง ประโยคตอไปนี้ StringBuffer s = new StringBuffer("Chaing Mai"); System.out.println("Length of " + s + " is " + s.length()); System.out.println("Capacity of " + s + " is " + s.capacity()); หลังจากการประมวลผล เราจะไดผลลัพธดังนี้ Length of Chaing Mai is 10 Capacity of Chaing Mai is 26 ตัวอยางตอไปนี้คงเปนตัวอยางสุดทายที่เราจะแสดงใหเห็นถึงการใช method อีกตัวหนึ่งในการ เปลี่ยนแปลงขอมูลที่อยูใ น string ใหอยูในรูปแบบของการกลับหัวกลับหาง (reverse) //ReverseString.java import java.io.*; class ReverseString { public static void main(String[] args) { //setting up a constant string StringBuffer string = new StringBuffer("I love Chaing Mai"); //create an empty string StringBuffer revStr = new StringBuffer(); revStr.append(string); //append string to revStr revStr.reverse(); //reverse it

}

}

System.out.println("Reverse of [" + string + "] is [" + revStr + "]");

ผลลัพธของการ run คือ Reverse of [I love Chaing Mai] is [iaM gniahC evol I]

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

129

หลังจากที่สราง string ดวยคา "I love Chiang Mai" แลวเราก็สราง object อีกตัวหนึ่งโดยไมมีการอาง ถึงคาใด ๆ ทั้งสิ้นดวยคําสั่ง StringBuffer revStr = new StringBuffer() หลังจากนั้นเราเชื่อม string เขากับ revStr ดวยการใช method append() เชนเดียวกับตัวอยางอื่น ๆ ที่เราไดทํามากอนหนานี้ เสร็จ จากการเชื่อมเราก็ใชคาํ สั่ง revStr.reverse() เพื่อทําการ reverse ขอมูลที่อยูใน revStr ที่เหลืออยูก็คือ การสงผลลัพธของการ reverse ไปยังหนาจอ ผูอานอาจสงสัยวาทําไมเราไมสราง object ดวยการสง string ไปใหกับ revStr ในตอนแรกที่เราสราง revStr เชน StringBuffer revStr = new StringBuffer(string) เราทําไมไดเพราะ Java ไดสราง method ในการสราง object จาก class StringBuffer ไวเพียงสามตัว คือ 1. StringBuffer() โดยไมใสเงื่อนไขใด ๆ 2. StringBuffer(int len) ตองใสขนาดของ buffer 3. StringBuffer(String str) ตองใส object จาก class String เทานั้น ยังมี method อีกมากมายที่เราสามารถนํามาใชในงานที่เกี่ยวของกับ string แตเราคงไมสามารถพูดในที่นี้ ไดหมด จึงเพียงแตหวังวาผูอานจะทําการคนควาตอไปเพื่อความเขาใจในเรื่องที่เกี่ยวของกับ string ตอไป ตารางที่ 4.2 แสดงถึง method ตาง ๆ ของ class StringBuffer ตาราง 4.2 method ของ class StringBuffer method capacity() length() setLength(new length) append(value) insert(index, value) replace(start index, end index, String) delete(start index, end index) deleteCharAt(index) setCharAt(index, character) charAt(index) substring(index) substring(start index, end index) toString() reverse()

ความหมาย ความจุของ StringBuffer ตัวนี้ ความยาวของ StringBuffer ตัวนี้ กําหนดความยาวของ StringBuffer ดวยความยาวใหม เชื่อมคาเขาทางดานหลังของ StringBuffer ตัวนี้ เพิ่มคาเขาสู StringBuffer ณ ตําแหนงที่กําหนด เปลี่ยนคาตามจุดที่กําหนด ดวย String ลบคาออกตามจุดที่กําหนด ลบตัวอักษรตามจุดที่กําหนด เปลี่ยนตัวอักษร ณ ตําแหนงทีก ่ ําหนด คาตัวอักษร ณ ตําแหนงที่กําหนด คา substring ตามจุดเริ่มตนที่กําหนดจนจบ String คา substring ตามจุดที่กําหนดเทานั้น object ที่มีคาของ String ที่อยูใน StringBuffer สลับตัวอักษรทุกตัวใน StringBuffer

การกําหนดใหขอ  มูลของ array เปน string (Array of Strings) เนื่องจากวา string เปน object ดังนั้นเราจึงสามารถทีจ ่ ะเก็บ string ไวใน array ได การจัดเก็บ string ไวใน array ก็ไมยุงยาก ก็คลาย ๆ กับที่เราเก็บขอมูลชนิดอื่นไวใน array นั่นเอง มาถึงตอนนี้ถาเราลอง มองยอนกลับไปดูการประกาศ method main() ของเรา เราจะเห็นการประกาศแบบนี้ public static void main(String[] args) { … ภายในเครื่องหมาย () เราจะเห็นการประกาศ String [] args ซึ่งเปนการประกาศใหตัวแปร args เปนตัว แปรที่ใชเก็บ array of strings ซึ่งการประกาศนี้ก็เหมือนกับการประกาศ array โดยทั่วไปเพียงแตเรา เปลี่ยนใหการจัดเก็บขอมูลมาเปน string เทานั้นเอง ลองมาดูโปรแกรมตัวอยางการสราง array of strings กันดู //ArrayOfStrings.java import java.io.*;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

130

class ArrayOfStrings { public static void main(String[] args) { //declare array of 5 strings String[] names = new String[5]; //initialize array names[0] = "Kafe"; names[1] = "River Side"; names[2] = "Good View"; names[3] = "Cottage"; names[4] = "Club G"; String word = names[2].substring(0, 4); System.out.println("First word from names[2] is " + word);

}

}

for(int i = 0; i < 5; i++) { System.out.println(names[i]); }

เราไดประกาศให names เปน array of Strings ทีส ่ ามารถเก็บขอมูลไดสูงสุด 5 ตัว ดวยคําสั่ง String[] names = new String[5]; หลังจากนั้นเราก็ใสขอมูลใหกับตําแหนงตาง ๆ ของ array names และเมื่อใสครบแลว เราดึงเอาคําแรกที่ อยูใน names[2] มาแสดง เมือ ่ เสร็จแลวเราก็แสดงขอมูลทั้งหมดไปยังหนาจอ ดวยการใช for – loop ผลลัพธของการ run คือ First word from names[2] is Good Kafe River Side Good View Cottage Club G โปรแกรมตัวอยางที่เห็นเปนโปรแกรมอยางงาย ที่เขียนขึ้นมาเพื่อแสดงการใช array of Strings กระบวนการตาง ๆ ที่สามารถทําไดกับ array โดยทั่วไปก็สามารถทําไดกับ array of Strings ดังนั้นผูอาน ควรยอนกลับไปดูเรื่องของ array ที่เราไดพูดถึง และลองประยุกตใชกระบวนการตาง ๆ กับ array of Strings ดูเพื่อใหเกิดความเขาใจมากยิ่งขึ้น สรุป ในบทนี้เราไดพด ู ถึงการเก็บขอมูลดวย array การใช String และ StringBuffer รวมไปถึงกระบวนการตาง ๆ ที่เราสามารถทําไดกับตัวแปร หรือ object ตาง ๆ ที่เกิดจาก class String และ class StringBuffer ผูอานควรทําความเขาใจกับ method ตาง ๆ ที่เราไดพด ู ถึงเพื่อการนําไปใชอยางมีประสิทธิภาพ จุดหลัก ๆ ที่เราไดพด ู ถึง คือ 9 9 9 9 9 9 9 9

การสราง array ในการเก็บขอมูลชนิดเดียวกันหลายตัวไวในตัวแปรตัวเดียว การเขาหาขอมูลแตละตัวใน array ดวยการใช index ขนาดของ array สามารถดึงออกมาจากตัวแปรคงที่ length Array สามารถที่จะเก็บขอมูลที่เปน array ได เราสราง object ที่เปน string จาก class String พรอมทั้งกําหนดคาที่ไมสามารถเปลีย ่ นแปลงได ขนาดของ string ตองดึงออกมาจาก method length() String มี method หลาย ๆ ตัวใหเราใชในการจัดการกับ string เราสราง string ที่สามารถเปลีย ่ นแปลงไดจาก class StringBuffer

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

9 9

การใช Array และ String

131

StringBuffer มี method หลายตัวที่เราเรียกใชในการจัดการกับ string ตาง ๆ ขนาดของ string จาก class StringBuffer หาไดจาก method length() และความจุของ object ที่มาจาก StringBufer หาไดดว ยการเรียกใช method capacity()

แบบฝกหัด 1. จงเขียนโปรแกรมทีร่ ับขอมูลทีเปน int จาก keyboard จํานวน 10 ตัว เก็บไวใน array พรอมทั้งหา คาสูงสุด คาต่ําสุด จํานวนของขอมูลที่เปนเลขคี่ทั้งหมด และจํานวนของขอมูลที่เปนเลขคูท  ั้งหมด 2. จงเขียนโปรแกรมทีใ่ ช Math.random() ในการสรางขอมูลจํานวน 100 ตัว เก็บไวใน array ใหแสดง ขอมูลทั้งหมดไปยังหนาจอโดยใหมจ ี ํานวนขอมูลเปน 5 แถว ๆ ละ 20 ตัว 3. จงเขียนโปรแกรมทีส ่ ราง array 2 มิติขนาด 3 x 3 จํานวน 2 ตัวทีม ่ ีขอมูลเปน int ใหใสขอมูลใน array ดวยการใช Math.random() ที่กําหนดใหคาของขอมูลทีส ่ รางขึ้นอยูระหวาง 1 – 9 หลังจาก นั้นใหนําเอา array 2 ตัวนี้มาบวกกัน (Matrix addition) เก็บผลลัพธทั้งหมดที่ไดไวใน array ตัวที่ สาม พรอมทั้งแสดง array ทั้งสามตัวไปยังหนาจอ 4. จงเขียนโปรแกรมทีร่ ับ object จาก class String จํานวนสามตัวจาก keyboard ใหตรวจสอบวา string ตัวไหนใหญทส ี่ ด ุ และ string ตัวไหนเล็กที่สด ุ แสดงผลลัพธไปยังหนาจอ 5. จงเขียนโปรแกรมทีใ่ ช array เก็บ string จํานวน 10 ตัวที่อยูใ นรูปแบบของ day/month/year เชน 02/10/00 ใหโปรแกรมตรวจสอบขอมูลที่อยูใน string ทุกตัว เสร็จแลวใหสง ผลลัพธทั้งหมดใน รูปแบบของ 2 October 2000 ไปยังหนาจอ 6. จงเขียนโปรแกรมทีใ่ ช array ในการเก็บ char จํานวน 10 ตัว ใหทําการ reverse ขอมูลทีอ ่ ยูใน array นี้ ผลลัพธที่ไดใหเก็บไวใน array ตัวเดิม 7. จงเขียนโปรแกรมทีใ่ ช StringBuffer เก็บ string จํานวน 10 ตัว ใหนาํ string ทั้งหมดไปเก็บไวใน string ตัวใหมโดยให string ทีม ่ ีจํานวนของ char นอยอยูท  างดานหนา และ string ที่มีจํานวนของ char มากอยูทางดานหลัง (เรียงจากนอยไปหามาก) 8. จงเขียนโปรแกรมทีใ่ ช array ในการเก็บชื่อของลูกคาจํานวน 20 ชื่อ ใหทาํ การคนหาชื่อของลูกคาที่มี ตัวอักษรขึ้นตน ตามที่ user เปนผูกําหนดจาก keyboard ใหแสดงชื่อทุกตัวที่มีอักษรขึ้นตนดังกลาว ออกทางหนาจอ 9. กําหนดให array1 และ array2 เปน array ทีเ่ ก็บ int จํานวนเทากับ 10 ตัวโดยที่ ขอมูลของแตละ array ไดถูกจัดเรียงใหอยูในรูปของ มากไปหานอย จงเขียนโปรแกรมที่นําเอาขอมูลของ array ทั้ง สองตัวมารวมกันโดยที่ยังรักษาคุณสมบัติของการเรียงจากมากไปหานอย เก็บไวใน array ตัวใหม แสดงผลลัพธของทั้งสาม array ออกทางหนาจอ 10. จงเขียนโปรแกรมทีร่ ับ String 1 ตัวที่ประกอบไปดวย ชื่อตน และนามสกุลทีถ ่ ูกแบงดวยชองวาง (space) เชน Micha Sapporo หลังจากนั้นใหแบง String ตัวนี้ออกเปน 2 ตัวใหเปน ชื่อตน 1 ตัว และนามสกุล 1 ตัว 11. จงปรับปรุงโปรแกรมในขอ 10 ใหทาํ หนาที่ลบชองวางที่อาจนําหนา และตามหลัง ชื่อที่นาํ เขาจาก keyboard 12. จงเขียนโปรแกรมทีร่ ับ String 2 ตัวจาก keyboard ใหทําการคนหาวา String ตัวทีส ่ องมีอยูใน String ตัวแรกหรือไม ถามี มีอยูกี่ตัว อยูท  ี่ตาํ แหนงใดบาง 13. จงเขียนโปรแกรมทีร่ ับ String 2 ตัวจาก keyboard ใหนําเอา String ตัวทีส ่ องไปใสไวในตําแหนงที่ ถูกกําหนดจาก user ถาตําแหนงที่ user กําหนดเปนไปไมไดใหนํา String นั้นไปใสไวดา นหลังของ String ตัวแรก 14. จงเขียนโปรแกรมทีท ่ ําหนาทีด ่ งั นี้

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 4 เริ่มตนกับ Java

การใช Array และ String

132

รับ String ในรูปแบบของ 112 Newell Street, Walla Walla, WA 99210 ทําการตัด String ใหอยูในรูปแบบของ No. Street: City: State: Zip:

112 Newell Street Walla Walla WA 99210

15. จงเขียนโปรแกรมทีท ่ ําการสลับคําทีม ่ ีอยูใน String เชน ถา String เปน I love Chiang Mai ผลลัพธ ที่ไดจากการสลับจะเปน Mai Chiang love I

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


เราไดเรียนรูถึงโครงสรางหลักของการเขียนโปรแกรมโดยทัว่ ไปจากบทกอน ๆ เราไดเรียกใช class ตาง ๆ (บาง class) ที่ Java มีใหในการเขียนโปรแกรม รวมไปถึงการสราง object จาก class String และ class StringBuffer ในบทนี้เราจะมาทําความเขาใจในเรื่องของการสราง class การสราง object จาก class ที่ เราสรางขึ้น การนําเอา class มาชวยแกโจทยและปญหาทางดานคอมพิวเตอร หลังจากจบบทนี้แลว ผูอานจะไดรับทราบในเรื่องของ o o o o o o o o

ความหมายของ class และการสราง class การสราง constructor การสราง method การ overload method การสราง object จาก class การใช attribute ตาง ๆ ของ class การสราง nested class การสราง และการเรียกใช package

Class และ การสราง class เราไดเห็นจากบทกอน ๆ วาเราตองกําหนดโปรแกรมที่เราเขียนขึ้นดวยคําวา class เสมอ แตเราไมไดพด ู ถึงเลยวา class คืออะไร โดยทั่วไปการเขียนโปรแกรมดวยภาษาที่เรียกกันวา Object-Oriented Programming (OOP) นั้นคําวา class มักจะหมายถึงคุณลักษณะ หรือคุณสมบัติ (prescription) ของวัตถุ ใดวัตถุหนึ่ง (ทีเ่ กิดจาก class นั้น ๆ) ซึ่งถาพูดแบบภาษาชาวบานทั่ว ๆ ไปเราอาจเรียก class ดังกลาววา เปนแมแบบของ class (อื่น ๆ ที่ตามมาก็ได) หรือวาเปนตัวกําหนดคุณสมบัติของ object ที่ไดถูกสรางขึ้น ถาเรามองไปรอบ ๆ ตัวเรา เราจะเห็นวัตถุหลากหลายชนิด เชน เกาอี้ keyboard ถวยกาแฟ และอะไรอื่น ๆ อีกมากมาย ซึ่งวัตถุหลายชิน ้ มีรูปรางหนาตาเหมือนกัน มีการใชสอยทีค ่ ลาย หรือ เหมือนกัน เชน เกาอี้มี สี่ขา หรือสามขา มีพนักพิง หรือไมมีพนักพิง แตการใชงานเหมือนกันคือ เอาไวนั่ง หรืออีกตัวอยางหนึ่ง เชน รถยนต มีสี่ลอ ขับเคลื่อนไปไดทั้งขางหนา และขางหลัง ตองใชนา้ํ มันเปนเชื้อเพลิง มีสีภายนอกที่ ตางกัน แตมค ี ณ ุ สมบัตท ิ ี่เหมือนกันคือเอาไวเดินทางไปยังที่ตาง ๆ และโดยทั่วไปแลวผูข  ับขี่สวนใหญจะ ไมรูถึงการทํางานของเครื่องยนตที่อยูภ  ายใน รูแตเพียงขอมูลที่จาํ เปนบางสวน เชนเปดประตูอยางไร start เครื่องยังไง เขาเกียรอยางไร อยางนี้เปนตน การเขียนโปรแกรมในรูปแบบของ OOP ก็เหมือนกัน ถา เราพัฒนาโปรแกรมใดสักโปรแกรมหนึ่งใหผูอน ื่ ใช ผูใชกลุม  นัน ้ ไมจําเปนที่จะตองรูวาเราเขียนอยางไร ควร รูเพียงแตวาจะใชสวนตาง ๆ ที่เราเขียนขึ้นอยางไร และนํากลับไปใชใหมไดอยางไร (เหมือนเชนที่เรา เรียกใช method ตาง ๆ จาก class String เราไมรูวาเขาเขียน code อยางไร รูแตวา ใชงานอยางไร) ถามองกลับไปดู class String ที่เราใชในบทที่สี่นั้น จะเห็นวาเราสามารถทีจ ่ ะใช method ตาง ๆ ที่มีโดย ไมมีการจํากัดจํานวนครั้งที่ใช โปรแกรมตัวไหนเรียกใชก็ได การทํางานก็ยังคงเหมือนเดิม ผลลัพธของ การเรียกใชก็เหมือนเดิม object ที่มาจาก class String ไมวาจะเปนตัวไหน เราก็สามารถทีจ ่ ะใช method ตาง ๆ กับ object เหลานี้ได ในการออกแบบ class นั้นโดยทั่วไปเราตองออกแบบใหเหมาะสมกับงาน ของเรา เชนถาโปรแกรมของเราตองวุนวายกับคนเราก็อาจออกแบบให class ของเรามีคุณสมบัตแ ิ ละ คุณลักษณะ ที่เกี่ยวของกับคน เชน มีชื่อ นามสกุล ที่อยู สถานะภาพ อาชีพ และอะไรอื่น ๆ ทํานองนี้ โดยทั่วไปการออกแบบ class นั้นมีสวนประกอบที่จําเปน และ สําคัญอยูส  องสวน คือ


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

134

o

Field หมายถึงตัวแปรสําหรับการเก็บขอมูลของ object ที่บงบอกถึงความเหมือน หรือ ความแตกตาง กันของ object ที่เกิดมาจาก class เดียวกัน หนังสือหลายเลมเรียก field ที่วานี้วา Data member หรือ สมาชิกของ class ที่เปนที่เก็บขอมูล หรือที่เราเรียกกันจนคุนปากวา variable (identifier)

o

Method หมายถึงกระบวนการ (operation) ตาง ๆ ที่เราสามารถทําไดกับ object นั้น ๆ ของ class ซึ่งกระบวนการตาง ๆ ทีท ่ ําไดสวนใหญจะกระทํากับ data member

Field หรือ Data member สามารถที่จะกําหนดใหเปนขอมูลไดทุกชนิด รวมไปถึงการเปนตัวอางอิง (reference) ถึง object ที่มาจาก class อื่น (เชน ตัวแปรทีม ่ ีชนิดเปน String หรือ array ที่เราไดพด ู ถึง กอนหนานี้) หรือแมแตกระทั่งการเปนตัวอางอิงถึง class ของมันเอง Method จะประกอบไปดวยชื่อของ method และชุดคําสั่งตาง ๆ ที่ตัวมันเองมีหนาทีใ่ นการทําตาม คุณลักษณะที่ไดถูกออกแบบไว ซึ่งโดยสวนใหญจะกระทํากับ data member (แตก็ไมจําเปนเสมอไป เชนในกรณีของ method main()) เพื่อใหเห็นภาพชัดเจนยิ่งขึ้น เรามาลองออกแบบ class ขึ้นมาสัก class หนึ่งที่เกี่ยวของกับ Student

class name

Data member

Instance variable

class Student { String id; String firstname; String lastName; String dateOfBirth; static int count = 0;

Class variable

Constructor Student(String iden, String fName, … … } Method

Parameter list

public int getCount() { return count; }

}

//method ตัวอื่น ๆ ที่เหลืออยู … …

ภาพที่ 5.1 ตัวอยางการสราง class Student

Class Student ที่เราสรางขึ้นประกอบไปดวยสวนประกอบสองสวนดังที่ไดกลาวไปแลว คือ สวนที่เปน data member และสวนที่เปน method ซึ่งภายในสวนสองสวนนี้ ยังมีสว นประกอบอื่นอีกทีม ่ ีความสําคัญ ตอการออกแบบ และการใช class กอนอื่นเรามาดูสวนประกอบของ data member กัน ตัวแปรที่เปนสมาชิกของ class (Class variable และ Instance variable) Object ที่เกิดมาจาก class นั้นเราเรียกกันวา instance ของ class และ object นี้จะมีสวนประกอบที่ class มีให คือ ตัวแปรตาง ๆ ที่อยูใน class ตัวแปรเหลานี้จะมีขอแตกตางกัน คือ อาจเปนตัวแปรที่เปน class variable และอาจเปนตัวแปรทีเ่ ปน instance variable หลังจากที่เราสราง object แลว object จะไดรับ copy ของตัวแปรที่ class มีให ซึ่งตัวแปรเหลานี้จะเปน ตัวบงบอกวา object ตัวไหนแตกตางกันอยางไร คาของตัวแปรของ object แตละตัวจะมีคาเหมือนหรือ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

135

แตกตางกันนั้นขึ้นอยูกับการกําหนดของโปรแกรมเอง เชน ถาเราสราง object สองตัวจาก class Student ขึ้นมาใชงาน object สองตัวนีจ ้ ะมี copy ของตัวแปรทั้งสี่ตวั ของมันเอง เราเรียกตัวแปรเหลานี้วา instance variable สวนตัวแปรอีกชนิดหนึ่งคือ class variable นั้นกําหนดไววา object ทุกตัวทีเ่ กิดจาก class จะใชตัวแปร ชนิดนีร้ วมกัน และตัวแปรนีส ้ ามารถที่จะกําหนดและสรางขึ้นมาใชได ถึงแมวา จะไมมี object เกิดขึ้นจาก class นี้ก็ตาม เพราะวาตัวแปรนี้เปนของ class ดังนั้นทั้ง class และ object ก็สามารถที่จะใชมันได ถาคา ของตัวแปรนี้เปลี่ยนไป object หรือ class ที่อา งการใชถึงตัวแปรตัวนี้ก็จะไดคาใหมที่เปลีย ่ นไป ซึ่งตรงกัน ขามกับตัวแปรที่เปน instance variable ถาหาก object ตัวไหนเปลี่ยนคาของตัวแปรใด ๆ (copy) คาที่ เปลี่ยนไปจะไมมีผลตอตัวแปรใด ๆ ใน object ตัวอื่น การประกาศใหตัวแปรใด ๆ ก็ตามเปน class variable นั้นเราตองใชคําสั่ง static นําหนาตัวแปรนั้นเสมอ ดังที่ไดแสดงในภาพที่ 5.2

class Student { static int count = 0; String String String String

Object ทุกตัว share ตัวแปร count

id; firstname; lastName; dateOfBirth;

0 Joe id firstNAme lastName dateOfBirth

ทั้ง Joe และ Jon มี copy ของตัวแปรเหลานี้

Jon id firstNAme lastName dateOfBirth

ภาพที่ 5.2 การใชตัวแปรแบบ class variable และแบบ instance variable

ตัวแปรทั้งสองชนิดมีการใชทแ ี่ ตกตางกัน และตางก็มีความสําคัญทั้งคู โดยทั่วไปการใช class variable นั้นนิยมใชในกรณีที่เราตองการที่จะเก็บคาที่เปนคาที่ object ทั้งหมดตองใชรวมกัน เชนคาคงทีต ่ าง ๆ ทีม ่ ี ความจําเปนใน class นั้น ๆ ตัวอยางของเราใช count เปนตัวแปรที่ใชรวมกันระหวาง object ตาง ๆ สวนตัวแปรที่เปน instance variable นั้นมีความจําเปนอยางมากในการออกแบบ class ตาง ๆ ทั้งนี้เพราะ ตัวแปรชนิดนี้จะเปนผูกําหนดความแตกตางระหวาง object ตาง ๆ ที่ไดถูกสรางขึ้นจาก class นั้น ๆ เชน object จาก class Student ที่ถูกสรางขึ้นอาจมี id ที่ไมเหมือนกัน ชื่อตน และ ชื่อสกุลทีแ ่ ตกตางกัน วัน เดือนปเกิดที่ไมเหมือนกัน อยางนี้เปนตน ขอแตกตางระหวาง class กับ object class เปนแมแบบทีม ่ ส ี มาชิกทั้ง data และ method ไมมีตัวตนขณะที่โปรแกรมกําลัง execute ไมมีการเปลี่ยนแปลงขณะโปรแกรม execute

object ตองเกิดมาจาก class ใด class หนึ่ง

มีตัวตนขณะโปรแกรมกําลัง execute สามารถเปลีย ่ นแปลงคาของ data ขณะ execute

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

136

Method จากแผนภาพที่ 5.1 เราจะเห็นวามี method อยูใน class Student ของเรา (บางสวน) method เปน กระบวนการ (ทีร่ วบรวมชุดคําสัง่ ) ที่เราสามารถเรียกใชใหทํางานตาง ๆ ใหเรา ซึ่งอาจเปนการทํางานที่ เกี่ยวของกับ ตัวแปรที่อยูใน class หรือกระบวนการอื่น ๆ ที่จาํ เปนของ class นั้น ๆ และเชนเดียวกันกับตัว แปรที่ไดกลาวไวกอนหนานี้ method ก็ไดถก ู แบงออกเปนสองชนิด คือ class method และ instance method Class method ก็คือ method ที่สามารถที่จะไดรับการประมวลผลถึงแมวา จะไมมี object อยูเลย ถาเรา มองยอนกลับไปดู method main() ของเรา เราจะเห็นวาไมมี object ใด ๆ เกิดจาก class ที่มี method main() อยูเลย และการประกาศใช class method ก็เชนเดียวกันกับ class variable เราตองใชคําสั่ง static นําหนาเสมอ สวน instance method นั้นเปน method ที่ตอ  งมีการใชรวมกันกับ instance variable ทั้งนี้เพราะวา method ประเภทนี้ถูกสรางขึ้นมาจาก class เดียวกันกับที่ object ถูกสรางขึ้นมา การกระทําใด ๆ ก็ตาม ตองทําผาน instance method เทานั้น การเขาหาตัวแปร และ method ของ class ในการที่จะเขาหาตัวแปรหรือ method ของ class นั้นไมวาจะเพื่ออะไรก็ตามแต เราจะตองเขาหาผานทาง object ของ class ตามดวย . (dot) และตามดวยชื่อของตัวแปร หรือ ชื่อของ method เชน studentA.firstName; หรือ studentB.getAge(); ในตอนนี้เราจะดูเพียงแควิธีการเขาหา แตตอไปเราจะดูเรื่องการกําหนดนโยบายของการเขาหาตัวแปร หรือ method เหลานี้ ถามี method หรือ ตัวแปรอยูเราก็เขาหาแบบที่ไดกลาวมาแลว Java จะฟองดวย error ถาหากอางถึงตัวแปรหรือ method ที่ไมไดถูกสรางขึน ้ เพื่อใหเห็นภาพของการสราง class รวมไป ถึงสวนประกอบตาง ๆ ของ class เรามาดู class Student ที่ไดถูกสรางขึ้นเพือ ่ เปนตัวอยาง //Student.java - Simple class for student import java.lang.Integer; import java.util.Calendar; class Student { String id; String firstName; String lastName; String dateOfBirth;

//student id //student's first name //student's last name //student's date of birth in //the form: dd/mm/yyyy static int count = 0; //number of object created //class constructor to initialize fields to given values Student(String iden, String fName, String lName, String dOfB) { id = iden; firstName = fName; lastName = lName; dateOfBirth = dOfB; count++; } //method to return count public int getCount() {

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

}

Objects และ Classes

137

return count;

//method to return student's id public String getId() { return id; } //method to returnstudent's first name public String getFirstName() { return firstName; } //method to return student's last name public String getLastName() { return lastName; } //method to return student's date of birth public String getDateOfBirth() { return dateOfBirth; } //method to calculate student's age from //year of birth public int getAge() { //retrieve a year String year = dateOfBirth.substring(6); //convert it to an int int birthYear = Integer.parseInt(year);

}

}

//get current year from system's calendar Calendar now = Calendar.getInstance(); int thisYear = now.get(Calendar.YEAR); //return the difference return thisYear - birthYear;

//method to display students' info to screen public void display() { System.out.print(getId() + " "); System.out.print(getFirstName() + " "); System.out.print(getLastName() + " "); System.out.println("Age: " + getAge()); }

เราไดกําหนดให class Student มี field อยูทั้งหมด 5 field คือ id, firstName, lastname, dateOfBirth, และ count โดยทีส ่ ี่ตวั แรกเปน instance variable ที่เอาไวเก็บขอมูลโดยเฉพาะของ object แตละตัวที่ ไดถูกสรางขึ้น และตัวสุดทายเปน class variable ที่เอาไวเก็บจํานวนของ object ที่ไดถูกสรางขึ้น เรายังไดสราง method อีก 7 ตัวซึ่งมีหนาทีใ่ นการทํางานทีต ่ างกัน โดยเฉพาะ method ที่มีชื่อเหมือนกัน กับ class นั่นก็คือ method Student Student(String iden, String fName, String lName, String dOfB) { id = iden; firstName = fName; lastName = lName;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

}

Objects และ Classes

138

dateOfBirth = dOfB; count++;

Student() เปน method พิเศษที่มีชื่อเรียกกันโดยทั่วไปวาเปน constructor ของ class ซึ่ง constructor นี้สวนใหญจะทําหนาทีใ่ นการกําหนดคาเบื้องตนใหกับ object ที่ไดถูกสรางขึ้นจาก class เชน กําหนดคา ใหกับ field ทุก field หรือบาง field (ทั้งนี้ตองแลวแตการออกแบบการทํางานของ constructor นั้น ๆ) ตัวอยางของเรากําหนดให constructor ทําการกําหนดคาใหกับ field ทุก field (ยกเวน class variable ที่ ชื่อ count) ใหมีคาเปนไปตามคาที่ไดรับเขามาจากตัวแปรทีอ ่ ยูใน parameter list แต constructor จะมี คุณสมบัติพิเศษคือ การกําหนดคานั้นจะไดรับการกระทําโดยอัตโนมัติ เราไมตองเรียกใช constructor การเรียกใช constructor นี้ Java จะเปนผูเรียกใหในตอนที่เราสราง object ขึ้นมา กอนที่เราจะพูดถึง constructor และการถูกเรียกใชงานโดยอัตโนมัตินั้นเรามาดูกันถึง method และ วิธีการสราง method รวมไปถึงการสงคาใหกับ method และการสงคากลับของ method การสราง method ในการสราง method นั้นเราจะตองกําหนดชือ ่ ใหกับ method กําหนด parameter (ถามี) กําหนดการสง คากลับของ method (ถามี) โดยทั่วไป method ไดถูกแบงออกเปนสองแบบ คือ o o

Method ทีส ่ งคากลับใหแกผท ู เี่ รียกใช method Method ทีไ ่ มมก ี ารสงคาใด ๆ กลับไปใหผูเรียก

โครงสรางของ method โดยทัว่ ไปจะมีรูปแบบดังนี้

ชนิดของคาที่สงกลับ เปนชนิดไหนก็ได

ชนิดของคาที่สงกลับ

ชื่อของ method

Parameter (ถามี)

ใชคําสั่ง void ถาไมมี คาที่ตองสงกลับ

returnType methodName( arg1, arg2, …, argn ) { // body of method … … }

ชุดคําสั่งตาง ๆ ที่ method ตัวนี้มีอยู (body of method)

ภาพที่ 5.3 การสราง method

เราลองหยิบเอา method getAge() จาก class Student มาดูกันเพื่อใหเกิดความเขาใจในเรื่อง สวนประกอบตาง ๆ ที่มีอยูใน method ที่วานี้ public int getAge() { String year = dateOfBirth.substring(6); int birthYear = Integer.parseInt(year);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

}

Objects และ Classes

139

Calendar now = Calendar.getInstance(); int thisYear = now.get(Calendar.YEAR); return thisYear - birthYear;

ถาเราแยกสวนประกอบตาง ๆ ออก เราก็จะไดขอมูลดังนี้ ชนิดของคาทีส ่ ง กลับ ชื่อของ method คือ Parameter ชุดคําสั่งคือ

int getAge ไมมี String year = dateOfBirth.substring(6); int birthYear = Integer.parseInt(year); Calendar now = Calendar.getInstance(); int thisYear = now.get(Calendar.YEAR); return thisYear - birthYear;

ถาสังเกตใหดจ ี ะเห็นวาดานหนาสุดของ method getAge() จะมีคําวา public อยู คําวา public นี้จะเปน ตัวกําหนดนโยบายการเขาหา method ซึ่งเราจะไดพูดถึงในตอนตอไป แตตอนนี้เราจะดูเฉพาะ สวนประกอบโดยทั่วไปที่ method ตองมี สวนประกอบทีส ่ ําคัญอีกสวนหนึ่งก็คือ คําวา return ในบรรทัดสุดทาย เนื่องจากวา method getAge() ของเราตองสงคากลับ ดังนั้นเราจึงจําเปนที่จะตองบอกให Java รูวาเรามีคา ที่ตองการสงกลับ ดังที่ได ประกาศไว ถาหากวาเราไมมก ี ารใช return พรอมทั้งคาทีต ่ อ  งการสงกลับ Java ก็จะฟองดวย error ตอน ที่เรา compile โปรแกรม เรามาลองดู method ที่ไมมีการสงคากลับใน class Student ของเรา ซึ่งมีอยูเพียงตัวเดียว คือ public void display() { System.out.print(getId() + " "); System.out.print(getFirstName() + " "); System.out.print(getLastName() + " "); System.out.println("Age: " + getAge()); } ชนิดของคาทีส ่ ง กลับ ชื่อของ method คือ Parameter ชุดคําสั่งคือ

ไมมี display ไมมี System.out.print(getId() + " "); System.out.print(getFirstName() + " "); System.out.print(getLastName() + " "); System.out.println("Age: " + getAge());

Method display() ทําหนาที่เปนเพียงตัวแสดงขอมูลของ object ที่เกิดจาก class Student ออกทาง หนาจอ โดยการเรียกใช method อื่น ๆ ที่มีอยูใน class Student การที่จะให method ไมตองสงคากลับ นั้นเราตองใช คําวา void นําหนาชื่อ method เสมอ และ method ที่มีคําวา void นําหนาตองไมมีคําวา return ใด ๆ ทีม ่ ีคาในการสงกลับ ยกเวนคําวา return ที่ตามดวย ; (semicolon) เทานั้น เชนถาเราใช void เราก็สามารถที่จะใช return ตามดวย ; หรือไมใชเลย อยางใด อยางหนึ่ง เพราะฉะนั้น method display() ที่เห็นก็สามารถที่จะเขียนไดอีกแบบหนึ่งดังนี้ public void display() { System.out.print(getId() + " "); System.out.print(getFirstName() + " "); System.out.print(getLastName() + " "); System.out.println("Age: " + getAge());

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

}

Objects และ Classes

140

return ;

ขอแตกตางระหวาง method ที่สงคา และ method ที่ไมสงคา method ที่สงคา มีคําวา return และ คาทีต ่ องสงกลับ

ขึ้นตน method ดวยชนิดของขอมูลที่ตอง สงกลับ

method ที่ไมสงคา ไมจําเปนตองมีคําวา return แตถามีจะตอง ตามดวย ; อยางเดียวเทานั้น ขึ้นตน method ดวยคําวา void เสมอ

กระบวนการทีเ่ กิดขึ้นเมือ ่ มีการใช parameter list เราลองมาดูโปรแกรมตัวอยางที่มีการสราง method ที่มีการใช parameter list กอนที่เราจะกลับมาดู class Student อีกครั้งหนึ่ง //Parameters.java class Parameters { public static void main(String[] args) { double radius = 2.0; double area = findArea(radius); }

}

System.out.println("Area of a circle is : " + area);

public static double findArea(double r) { return Math.PI * r * r; }

โปรแกรม Parameters.java สราง method ทีเ่ ราเรียกวา class method ขึ้นมาใชงานหนึ่งตัว (การ ประกาศให method เปน class method ก็เหมือนกับการประกาศใหตัวแปรเปน class variable เราตอง ใชคาํ วา static นําหนา) ซึ่ง method นี้มีหนาที่ในการคํานวณหาพื้นที่ของวงกลมที่มรี ัศมีที่กําหนดไวใน ตัวโปรแกรม (ในที่นี้คือ 2) method findArea() มี Parameter หนึ่งตัวที่มช ี นิดเปน double และจะสงคา ของพื้นที่ทค ี่ ํานวณไดกลับไปใหผูเรียก ซึ่งในที่นี้คือ class Parameters การเรียก method findArea(() นั้นเราเรียกดวยประโยค double area = findArea(radius); ซึ่งเมื่อ Java เห็นการเรียกเชนนี้ Java ก็จะไป execute method findArea() ดวย parameter ที่มีชนิด เปน double และสงคา 2.0 ไปให หลังจากที่คํานวณคาพืน ้ ที่ไดแลวก็จะสงกลับออกมา และนําไปเก็บไว ในตัวแปรชื่อ area ภาพที่ 5.4 แสดงการสงคาผานทาง parameter list

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

141

class Parameters { public static void main(String[] args) { double radius = 2.0; double area = findArea(radius); … … }

คาของ radius จะถูกสง เขามาไวในตัวแปร r

… …

ชนิดของคาที่สงกลับ ออกมา ตองเปนชนิด เดียวกัน

public static double findArea(double r) { return Math.PI * r * r; }

คาที่ไดจากการคํานวณจะถูก สงไปให ตัวแปร area

ภาพที่ 5.4 การสง parameter ใหกับ method และการสงคากลับออกจาก method

การสงคาผานทางตัวแปรที่อยูใน parameter list นั้นมีอยูส  องแบบคือ 1) การสงที่เรียกวา pass-by-value หรือการสงเฉพาะคาเขาไปใน method นั้น ๆ และ 2) การสงแบบที่เรียกวา pass-by-reference ในการสง คาที่เปน primitive type นั้น Java จะกําหนดใหการสงเปนแบบ pass-by-value เทานั้น ซึง่ ไดแสดงไวใน ภาพที่ 5.5 class PassByValue { public static void main(String[] args) { int total = 10; … … int newTotal = increment(total); … } …

การประมวลผลทํา กับ copy ของ total

total 10

copy ของ total 10

public static int increment(int sum) { sum += 10; }

return sum; ตัวแปร sum อาง ถึง copy ของ total ที่อยูใน main()

ภาพที่ 5.5 การสงคาแบบ pass-by-value

ตัวแปร total ทีอ ่ ยูใน method main() นั้นจะไมไดรับผลกระทบจากการเปลีย ่ นคา ที่เกิดขึ้นภายใน method increment() ทั้งนี้ก็เพราะวา กระบวนการที่เกิดขึ้นไมไดกระทํากับตัวแปร total แตเปนการ กระทํากับ copy ของ total

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

142

การสงคาไปยัง method แบบ pass-by-value นี้คาที่สงเขาไปจะถูกนําไปใชภายในตัว method เทานั้น การเปลี่ยนแปลงใด ๆ ที่เกิดขึน ้ จะไมมีผลกระทบกับตัวแปรทีเ่ ปนเจาของคานั้น ภายนอก method เลย ซึ่ง ตรงกันขามกับ การสงคาในแบบที่เรียกวา pass-by-reference ลองมาดูตัวอยางโปรแกรมการสงคาแบบ pass-by-value กัน //PassByValue.java class PassByValue { public static void main(String[] args) { int total = 10; System.out.println("Before calling: total is " + total);

}

System.out.println("Value returns from increment() is " + increment(total)); System.out.println("After calling: total is " + total);

public static int increment(int sum) { sum += 10;

}

}

return sum;

ผลลัพธที่ไดจากการ run คือ Before calling: total is 10 Value returns from increment() is 20 After calling: total is 10 increment() ถูกเรียกภายใน main() จากประโยค System.out.println("Value returns from increment() is " + increment(total)); ซึ่งมีการสงคาของ total ไปให (ซึ่งมีคาเปน 10) คานี้ถูก นําไปใชใน increment() ผานทางตัวแปรทีช ่ อ ื่ วา sum ภายใน increment() ตัวแปร sum ถูกเปลี่ยนคา ดวยการนําเอา 10 ไปบวกเพิ่ม ทําให sum มีคาเปน 20 ซึ่งคานี้จะถูกสงกลับไปยัง main() ทําใหการ แสดงผลทางหนาจอมีคาเปน 20 แตหลังจากนั้น เรากําหนดใหมีการแสดงคาของ total อีกครั้งหนึ่ง ซึ่ง ผลลัพธที่ไดคอ ื คาของ total ยังคงเปน 10 อยู จะเห็นวาคาของ total ที่ไดรับการเปลี่ยนแปลงภายใน increment() (ผานทางตัวแปร sum) ไมมีผลตอตัวแปร total อยางใดเลย การเปลี่ยนแปลงเกิดและตาย ภายใน increment() เทานั้น เรามาลองดูโปรแกรมตัวอยางอีกโปรแกรมหนึ่ง //PassByValue2.java class PassByValue2 { public static void main(String[] args) { String myString = "Business Computers"; System.out.println("Before string is: " + myString); changeString(myString); //calling changeString() }

System.out.println("After myString is: " + myString);

public static void changeString(String string) { System.out.print("\tInside changeString(), "); System.out.println("myString is: " + string); string = "at Far Eastern College";

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

}

Objects และ Classes

143

}

โปรแกรม PassByValue2.java สราง string หนึ่งตัวมีขอความวา "Business Computers" และสง string นี้ไปให method changeString() ซึ่งทําหนาที่ในการเปลี่ยนคาของ string ที่สงเขามาใหเปน "at Far Eastern College" แตหลังจากที่เรา run โปรแกรมดู เราก็ไดผลลัพธตามที่เห็นดานลางนี้ Before string is: Business Computers Inside changeString(), myString is: Business Computers After myString is: Business Computers จะเห็นวาการเปลี่ยนแปลงคาของ string ทีส ่ งผานเขามานั้นจะเปนเพียงการเปลี่ยนแปลงแบบชั่วคราว เทานั้น การเปลี่ยนแปลงเกิดขึ้นภายใน changeString() และไมมีผลกระทบใด ๆ กับคาของตัวแปร myString แตอยางใดเลย การสงคาแบบอางอิง pass-by-reference การสงคาแบบ pass-by-reference นั้น สิ่งที่เราสงเขาไปใน method นั้นไมใชคา ของตัวแปร แตเปน ตัวอางอิงถึงตัวแปร หรือ object นั้น ๆ โดยตรง เราอาจพูดไดวาสิ่งที่เราสงไปนั้นเปนที่อยู หรือ address ของตัวแปร หรือ object นั้น ๆ ก็ได เรามาลองดูตัวอยางการสงแบบ pass-by-reference กันในภาพที่ 5.6

public static void main(String[] args) { Circle red = new Circle(5.0); … … … ทั้ง red และ red.change(red, 2.0); copy ของ red … ตางก็อางถึง object เดิม สราง copy ของ red

red reference

Circle object Radius: 5.0

copy made

copy of red reference

c อางถึง copy ของ red ประโยค c.changeRadius(radius) ทําการเปลี่ยนแปลงขอมูล ของ object เดิมผานทาง copy ของ red

public Circle change(Circle c, double radius) {

}

c.changeRadius(radius); return c;

ภาพที่ 5.6 การสงแบบ pass-by-reference

ตัวอยางการสงแบบ pass-by-reference ที่เห็นในภาพที่ 5.6 นั้นเราสราง object จาก class Circle หนึ่ง ตัว โดยใหมช ี ื่อวา red และมี radius เทากับ 5.0 เราเรียก method change() ผานทาง object red ดวย การสง object red และคาใหมของ radius ไปให เมื่อ method change() ถูกเรียกดวย parameter ดังกลาว Java จะทําการสราง copy ใหกับ red และจัดเก็บ copy นี้ไวที่ c เนื่องจากวาทั้ง red และ c ตาง ก็อางถึง object ตัวเดียวกัน ดังนั้นการเปลี่ยนแปลงใด ๆ ที่เกิดขึ้นยอมมีผลกระทบตอ object ตัวเดิมทีท ่ งั้ red และ copy ของ red อางถึง (หรือเปนตัวแทนอยู) เราไดสราง method changeRadius() ขึ้นมาเพื่อใชในการเปลี่ยนคาของ radius ซึ่ง code ทั้งหมดของ โปรแกรมตัวนี้ มีดังนี้

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

144

//PassByReference.java //a Circle class to demonstrate pass-by-reference scheme class Circle { private double radius; //a radius of a circle //constructor to initialize radius Circle(double r) { radius = r; } //method to calculate area of a circle public double area() { return Math.PI * radius * radius; } //a method to change radius of a given circle public Circle change(Circle c, double radius) { c.changeRadius(radius); //calling method changeRadius() return c; //with a given radius } //a method to change a given radius private void changeRadius(double r) { radius = r; }

}

//a method to return radius public double getRadius() { return radius; }

//a class to test pass-by-reference scheme class PassByReference { public static void main(String[] args) { //create a red circle with a radius of 5.0; Circle red = new Circle(5.0); //calculate area of a red circle double area = red.area(); System.out.println("Radius of red circle is " + red.getRadius()); System.out.println("Area of red circle is " + area);

}

}

//change radius of a red circle red.change(red, 2.0); area = red.area(); System.out.println("Radius of red circle now is " + red.getRadius()); System.out.println("Area of red circle now is " + area);

เรามี class อยูสอง class โดยที่ class ตัวแรก หรือ class Circle เปน class ที่เอาไวใชสรางวงกลม ตาง ๆ รวมไปถึง method หรือกระบวนการตาง ๆ ทีเ่ ราตองการใชในการเปลี่ยนแปลง หรือกําหนดคาใหกับ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

145

วงกลมนั้น ๆ สวน class ตัวทีส ่ องเปน class ที่ใชสําหรับการทดสอบ การสราง object จาก class Circle และตรวจสอบการสงคาแบบ pass-by-reference หลังจากที่ทดลอง run เราก็ไดผลลัพธดังนี้ Radius of red circle is 5.0 Area of red circle is 78.53981633974483 Radius of red circle now is 2.0 Area of red circle now is 12.566370614359172 จากผลลัพธเราจะเห็นวาประโยคที่แสดงคาของ radius นั้นแสดงคาไดถูกตองทั้งกอน และหลังการ เปลี่ยนแปลงคาของ radius สิ่งที่เราตองจําไวในเรื่องของการสงคาใหกับ method ก็คือ การสงคาที่เปน primitive type เชน int หรือ double นั้น method จะไดรับแตเพียงคาเทานั้น การเปลี่ยนแปลงใด ๆ ภายใน method จะไมมีผลกระทบ ตอตัวแปรดานนอก แตถาเราสง object ไปให method การเปลี่ยนแปลงที่เกิดขึ้นภายใน method (ตอ ตัวแทนของ object นั้น ๆ) จะมีผลกระทบตอ object ที่อยูภายนอกดวย สมมติวาเราตองการที่จะทําการสลับคาของตัวแปรสองตัว ผานทาง method เราจะทําอยางไร? เรามา ลองดูตัวอยางแรกกันกอนวาจะทําใหเราไดหรือไม //Swap.java import java.io.*; class Values { int val1; int val2; //default constructor Values() { val1 = val2 = 0; } //assignment constructor Values(int a, int b) { val1 = a; val2 = b; }

}

//display val1 and val2 public void show() { System.out.println("(" + val1 + ", " + val2 + ")"); }

class Swap { public static void main(String[] args) { //create two objects from Values Values obj1 = new Values(10, 20); Values obj2 = new Values(30, 50); obj1.show(); obj2.show();

//display values of obj1 //display values of obj2

swap(obj1, obj2); //swap contents of obj1 and obj2 obj1.show(); obj2.show();

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

146

} //swapping contents of given objects private static void swap(Values pointA, Values pointB) { Values temp = new Values();

}

}

temp = pointA; pointA = pointB; pointB = temp;

//copy pointA to temp //copy pointB to pointA //copy temp to pointB

เรากําหนดใหการสลับคาของ object ทั้งสองเกิดขึ้นภายใน swap() ซึ่งเราคิดวานาจะทําได 100% แต หลังจากที่ run โปรแกรมดู เรากลับไดผลลัพธดังนี้ (10, (30, (10, (30,

20) 50) 20) 50)

ซึ่งบอกใหเรารูว า swap() ของเราใชไมได เราตองเปลี่ยนแปลง code ของ swap() ใหมเพื่อใหการสลับ เกิดขึ้นจริง และหลังจากที่เราเปลี่ยน code ใหเปน private static void swap(Values pointA, Values pointB) { Values temp = new Values(); temp.val1 = pointA.val1; temp.val2 = pointA.val2; pointA.val1 = pointB.val1; pointA.val2 = pointB.val2;

}

pointB.val1 = temp.val1; pointB.val2 = temp.val2;

ผลลัพธที่เราไดคือ (10, (30, (30, (10,

20) 50) 50) 20)

ซึ่งแสดงถึงการสลับคาที่ไดผลจริง สาเหตุที่ swap() ตัวแรกของเราทํางานไมได ก็เนื่องจากวา การ เปลี่ยนแปลงคาของ object เกิดขึ้นจาก copy ของ object ทั้งสองที่มาจาก parameter ไมใชตัว object จริง ๆ ดังนั้นการเปลี่ยนแปลงที่เกิดขึ้นจึงเกิดขึ้นภายในตัว swap() ไมมีผลกระทบใด ๆ กับ object ภายนอกเลย เราตองทําการเปลี่ยนคาใหกับสมาชิกที่อยูใน object นั้นโดยตรงดังเชนที่ swap() ตัวทีส ่ อง ไดแสดงไว เราไดพูดถึง class Student ที่เราสรางคางไวโดยเราไดสาํ รวจ การสราง method ตาง ๆ รวมไปถึงการสง คาเขาสู method ตอนนี้เราจะมาดูถึงรายละเอียดของ method ตาง ๆ ที่มีอยูใน class Student รวมไปถึง โปรแกรมที่เรียกใช object ที่เกิดจาก class Student กอนที่เราจะพูดถึง method ทีม ่ ีอยูใน class Student เรามาดูตัวโปรแกรมที่เรียกใช method เหลานี้ดู //TestStudent.java

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

147

class TestStudent { public static void main(String[] args) { //create two student objects with given info. Student stu1 = new Student("19757", "Jim", "Jones", "02/10/1962"); Student stu2 = new Student("20135", "Ray", "Smith", "12/09/1977"); //display each student's info. stu1.display(); stu2.display(); //display total number of students System.out.println("Total number of objects created: " + stu1.getCount());

}

}

//access field in class via object String date = stu1.dateOfBirth; System.out.println("Date of birth of stu1 is " + date);

เราไดสราง object stu1 และ stu2 จาก class Student ดวยขอมูลดังที่เห็น Student stu1 = new Student("19757", "Jim", "Jones", "02/10/1962") Student stu2 = new Student("20135", "Ray", "Smith", "12/09/1977") หลังจากนั้นเราก็เรียกใช method display() ในการแสดงผลขอมูลของ object ทั้งสองตัว โดยที่เราได ออกแบบ method display() ของเราใหมีการเรียกใช method อื่น ๆ ที่มีอยูใน class Student ดังนี้ public void display() { System.out.print(getId() + " "); System.out.print(getFirstName() + " "); System.out.print(getLastName() + " "); System.out.println("Age: " + getAge()); return ; } ผูอานจะสังเกตไดวาเราเรียก method getId() getFirstName() getLastName() และ method getAge() ภายในประโยคของ System.out.println(…) ซึ่ง method เหลานี้จะสงคาของ field ตาง ๆ ที่ ไดถูกกําหนดไวใหกับประโยคในการแสดงขอมูลไปยังหนาจอ หลังจากที่ขอมูลของ object ทั้งสองตัวไดถก ู แสดงไปยังหนาจอแลว เราก็เรียกประโยค System.out.println("Total number of objects created: " + stu1.getCount()); String date = stu1.dateOfBirth; System.out.println("Date of birth of stu1 is " + date); สําหรับการแสดงจํานวนของ object ที่ไดถูกสรางขึ้นทั้งหมด และวัน เดือน ป เกิดของ object ทีช ่ ื่อ stu1 ไปยังหนาจอ และผลลัพธของการ run ที่ไดคอ ื 19757 Jim Jones Age: 41 20135 Ray Smith Age: 26 Total number of objects created: 2 Date of birth of stu1 is 02/10/1962

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

148

ผูอานตองกําหนดใหการเรียก method ที่มีอยูใน class ผานทาง object ที่ไดสรางขึ้น ดวยการใช . (dot) ตามดวยชื่อของ method ที่ตอ  งการเรียกใช เชน stu1.display(); เชนเดียวกันกับการเรียกใช data member เราก็ตองขึ้นตนดวยชื่อของ object ตามดวย . (dot) ตามดวย ตัวแปรทีต ่ องการใช เชน stu1.dateOfBirth; เนื่องจากวาเราไมไดกําหนดนโยบายการเขาหา ตัวแปร หรือ method ที่มอ ี ยูใน class ดังนั้นการเขาหาจึง ไมขอกําหนดใด ๆ เราสามารถทีจ ่ ะเขาหาขอมูลทุกตัวโดยไมมีขอจํากัด กอนที่เราจะพูดถึงนโยบายการ เขาหาขอมูลทีอ ่ ยูใน class เราอยากที่จะพูดถึง method getAge() ที่มีอยูใน class Student สักเล็กนอย method getAge() ไดถูกออกแบบใหทําการคํานวณหาอายุดวยการหาจากการลบปเกิด ออกจากป ปจจุบัน ดังนั้นเราจึงตองเรียกใช method จาก class Calendar ในการคํานวณหาปปจจุบัน ดังนี้ public int getAge() { //retrieve a year String year = dateOfBirth.substring(6); //convert it to an int int birthYear = Integer.parseInt(year);

}

//get current year from system's calendar Calendar now = Calendar.getInstance(); int thisYear = now.get(Calendar.YEAR); //return the difference return thisYear - birthYear;

กอนที่เราจะคํานวณหาอายุได เราตองดึงเอา field ที่เปนปเกิดที่อยูใ นรูปแบบของ dd/mm/yyyy ออกมา กอนดวยการใช method substring() ที่เราไดพูดไวกอนหนานี้ เมื่อไดแลวเราก็เปลี่ยน string ที่มีคาเปน ปเกิดนี้ใหเปน int ดวยการเรียกใช Integer.parseInt() หลังจากนั้นเราก็ดึงเอาปปจจุบน ั ออกจากเครื่องดวยคําสั่ง Calendar now = Calendar.getInstance(); int thisYear = now.get(Calendar.YEAR); ซึ่งกอนที่เราจะดึงปออกไดเราตองสราง instance จาก class Calendar กอนและเมื่อไดแลวเราก็ใช method get() ในการดึงเอาปปจจุบันออกมา กระบวนการที่เหลืออยูก็คือการสงสวนตางระหวางปปจจุบัน กับปเกิดออกไปยังผูท  ี่เรียกใช method นี้ (การดึงเอาคาของปออก ผูอานตองระวังในเรื่องของปที่ใชใน เครื่อง ณ เวลานั้นดวยวาอยูในรูปแบบของ พุทธศักราช หรือ คริสตศักราช Windows ใหม ๆ ยอมใหมีการ ตั้งคาตามตําแหนงทีต ่ ั้งของประเทศนั้น ๆ) การสราง class Student ของเรานั้นเราไมไดกําหนดนโยบายการเขาหา field หรือ method ตาง ๆ ของ เราอยางไรเลย ผูอานคงสังเกตเห็นวา ตัวแปรทุกตัวของเราไมมีคําใด ๆ นําหนาเลย เชน private public หรือแมกระทั่งคําวา protected หัวขอตอไปจะพูดถึงเรื่องของการกําหนดนโยบายการเขาหาตัวแปร และ method ของ class วาจะมีประโยชนอยางไรในการออกแบบ class (ผูอานลองตั้งคําถามใหตัวเองกอน เริ่มหัวขอถัดไปวา ถาใสคําวา private หนาตัวแปรทุกตัวจะมีผลตอโปรแกรม TestStudent.java อยางไร ถาใสหนา method ตาง ๆ หละ?)

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

149

การกําหนดนโยบายในการเขาหาสมาชิกของ class (attributes) จาก class Circle ของเราที่ไดสรางขึ้น ในการประกาศตัวแปร radius นั้นเราไดกําหนดใหมค ี ําวา private อยูดานหนาของตัวแปร ดังนี้ private double radius; ทําไมเราถึงทําเชนนี้? สาเหตุที่เราทําเชนนี้ก็เพื่อที่จะกําหนดการเขาหาตัวแปรตัวนี้ โดยทั่วไปแลวถาเราไมใสคาํ วา private ไว หนาตัวแปรใด เราก็สามารถทีจ ่ ะเขาหาตัวแปรตัวนี้ ผานทางโปรแกรมอื่น ๆ ที่เรียกใช class Circle การ กําหนดนโยบายของการเขาหานั้น เราสามารถทําไดสวี่ ิธี คือ 1. 2. 3. 4.

ไมใชคําใด ๆ นําหนาตัวแปร (friendly) ใชคาํ วา private นําหนาตัวแปร (not too friendly) ใชคาํ วา public นําหนาตัวแปร (friendly) ใชคาํ วา protected นําหนาตัวแปร (somewhat friendly)

ถาเราไมใชคาํ ใด ๆ นําหนาตัวแปรการเขาหาตัวแปรตัวนีจ ้ ะทําไดเฉพาะ class ที่อยูภายในพื้นที่เดียวกัน เชนภายใน class เดียวกัน หรือภายใน package (ดูเรื่องการสรางและใช package ทายบท) เดียวกัน ดัง โปรแกรมตัวอยางที่แสดงใหดน ู ี้ //Access.java class Dot { //no access control String name; int value;

}

Dot(String s, int v) { name = s; value = v; }

class Access { public static void main(String[] args) { Dot myDot = new Dot("I am a dot.", 10);

}

}

//access both name and value fields from class Dot System.out.println("Name is " + myDot.name); System.out.println("Value is " + myDot.value);

เมื่อเรา run ดูผลลัพธที่ไดคือ Name is I am a dot. Value is 10 โปรแกรม Access.java สามารถทีจ ่ ะเขาหา field ทั้งสองที่เราสรางขึ้นใน class Dot ของเราผานทาง object ชื่อ myDot (หมายความวาใคร ๆ ก็เขาหาตัวแปรของเราไดถาเขารูวาเรามีตัวแปรอะไรบาง – อันตราย?) ทีนี้เราลองนําเอาคําวา private ไปใสไวหนาตัวแปรทั้งสองของเรา ดังนี้ private String name;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

150

private int value; การ compile โปรแกรมอีกครั้งหนึ่งจะทําใหเกิด error ดังนี้ Access.java:20: name has private access in Dot System.out.println("Name is " + myDot.name); ^ Access.java:21: value has private access in Dot System.out.println("Value is " + myDot.value); ^ 2 errors เราไมสามารถที่จะอางถึงตัวแปรทั้งสองไดเพราะคําวา private เราตองเขาหาดวยวิธีอื่น เชน เขียน method ที่สงคาของตัวแปรทัง้ สองกลับ (โดยเขียนไวใน class Dot) เหมือนกับที่เราไดทําไวใน class Circle เรากําหนดใหตวั แปร radius ของ class Circle เปน private data member ดังนั้นเราจึงตองเขียน method ในการเขาหาตัวแปร radius ของเรา ดังนี้ public double getRadius() { return radius; } เพราะฉะนั้นถาเราไมตองการใหโปรแกรม หรือ ผูใด (object) เขาหาตัวแปรของเรา เราก็นําคําวา private ไปแปะไวดานหนาของตัวแปรนั้น ๆ ถาสังเกตใหดีจะเห็นวา method changeRadius() ใน class Circle ก็ มีคําวา private อยูดานหนาเหมือนกัน ทั้งนี้ก็เพราะวาเราไมตอ  งการใหใครเขาหา method ตัวนี้ยกเวน method ที่อยูภ  ายใน class เดียวกัน การเขาหา method นี้ผานโปรแกรม หรือ object ตัวอื่นจะทําไมได และ Java compiler จะฟองดวย error ทันที เราจะกลับมาดูคําวา protected ในโอกาสตอไป ทั้งนี้เพราะคํา ๆ นี้มีเงื่อนไขซับซอนอยูพอสมควร สําหรับ คําวา public นั้นจะยอมใหทุกโปรแกรม หรือ object เขาหาตัวแปร หรือ method ไดโดยไมมีเงื่อนไขใด ๆ ทั้งสิ้น การกําหนดนโยบายการเขาหาตัวแปรหรือ method ทําใหการควบคุมโปรแกรมทําไดดย ี ิ่งขึ้น อะไรทีผ ่ ูใช ไมควรรูไมควรเห็น เราก็ซอนสิง่ เหลานี้ไว การกระทําในลักษณะนี้เราเรียกวา encapsulation ซึ่งเปนหนึ่ง ในขอกําหนดของการออกแบบและเขียนโปรแกรมในรูปแบบของ OOP ในสวนตัวของผูเขียนแลว ชอบที่ จะใช private กับตัวแปรทุกตัว และ method บางตัวที่ไมมีการเขาหาจากภายนอก เพราะจะทําใหการใช ตัวแปรมีขอจํากัด สวนที่เขาหาขอมูลเหลานีข ้ องเราไดเปนไดเฉพาะ method ที่เราไดกําหนดไวเทานั้น Constructor อีกครัง ้ Constructor มีไวสําหรับการกําหนดคาเบื้องตนใหกับตัวแปรที่อยูใ น class และการเรียกใช constructor นั้นเราไมตองทําโดยตรง constructor จะถูกเรียกโดยอัตโนมัติผา นทางการสราง object จาก class ดังที่ ไดแสดงไวในโปแกรมที่สราง object จาก class Circle จากประโยคของการสรางวงกลมทีว่ า Circle red = new Circle(5.0); ขั้นตอนที่เกิดขึน ้ เมื่อประโยคนีถ ้ ูก execute คือ Constructor ของ Circle ถูกเรียกดวยคา 5.0 ซึ่งหมายความวาตัวแปร radius ที่อยูใน class Circle จะ ไดรับคาที่กําหนดให คือ 5.0 หลังจากนั้นตําแหนง หรือ address ของ object ที่ถูกสรางและกําหนดคานี้ จะถูกเก็บไวใน red เพื่อใหเห็นภาพชัดขึ้น เราจะเพิ่มประโยคดานลางนี้เขากับ constructor ของ class Circle System.out.println("Constructor activated with parameter value of " + radius);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

151

เพราะฉะนั้น constructor ของ class Circle ก็จะเปน Circle(double r) { radius = r; System.out.println("Constructor activated with value of " + radius); } และเราจะลองสราง object สองตัวจาก class Circle ดังนี้ class PassByReference { public static void main(String[] args) { Circle red = new Circle(5.0); Circle blue = new Circle(3.5); } หลังจากที่ compile และ run ผลลัพธที่ไดคอ ื Constructor activated with value of 5.0 Constructor activated with value of 3.5 เราจะเห็นวา object สองตัวถูกสรางดวย radius ที่ตางกัน คือ 5.0 และ 3.5 และทั้ง ๆ ที่ไมมีประโยคของ การแสดงผลใน method main() ใด ๆ เลย เรากลับไดผลลัพธดังที่เห็น ทั้งนีก ้ ็เพราะวา constructor ของ เราที่มีอยูใ น class Circle ไดรับการเรียกใชโดยอัตโนมัติ เราสามารถทีจ ่ ะสราง constructor ใหกับ class ไดมากกวาหนึ่งตัวทั้งนี้การกระทําดังกลาวจะตองอยู ภายใตเงื่อนไขที่ Java กําหนดไว คือ parameter ที่สงไปยัง constructor ตองไมมีจํานวนที่เทากัน และ ถาจํานวนของ parameter เทากัน ชนิดของ parameter ตองไมเหมือนกัน (หนังสือเกือบทุกเลมเรียก ขั้นตอนนี้วาการกําหนด signature) ลองดูโปรแกรมตัวอยาง //TestMean.java class Mean { private double x, y, z; //constructor with one value Mean(double value) { x = value; y = 0.0; z = 0.0; } //constructor with two values Mean(double value1, double value2) { x = value1; y = value2; z = 0.0; } //constructor with three values Mean(double value1, double value2, double value3) { x = value1; y = value2; z = value3; }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

}

Objects และ Classes

152

public double findMean() { return (x + y + z) / 3; }

class Mean ของเรามี constructor อยูสามตัว โดยที่ตัวแรกมี parameter หนึ่งตัว constructor ตัวทีส ่ อง มี parameter สองตัว และ constructor ตัวทีส ่ ามมี parameter สามตัว ภายใน class เราไดสราง method findMean() สําหรับการคํานวณหาคาเฉลี่ยของตัวแปรทั้งสามของ class และเราไดเขียน โปรแกรมสําหรับตรวจสอบการใช constructor ดังกลาวดังนี้ class TestMean { public static void main(String[] args) { //create objects with diferent parameters Mean m = new Mean(12.0); Mean n = new Mean(10.0, 20.0); Mean p = new Mean(10.0, 20.0, 30.0);

}

System.out.println("Mean of m is " + m.findMean()); System.out.println("Mean of n is " + n.findMean()); System.out.println("Mean of p is " + p.findMean());

}

โปรแกรม TestMean.java ประกาศใช object จาก class Mean สามตัวดวยจํานวนของ parameter ที่ ตางกัน คือ หนึง่ ตัว สองตัว และสามตัวตามลําดับ หลังจากที่เราเรียก method findMean() สําหรับ object ทั้งสามตัวแลว ผลลัพธที่เราไดจากการ run คือ Mean of m is 4.0 Mean of n is 10.0 Mean of p is 20.0 จะเห็นวา Java เลือกใช constructor ไดถูกตองตามการออกแบบที่เรากําหนดไว ซึ่งวิธีการแบบนี้เรา เรียกวา constructor overloading เรามาลองดูการ overload ของ constructor ที่มีจํานวนของ parameter เหมือนกันแตตางชนิดกันดู อีกสักตัวอยางหนึ่ง //TestMean1.java class Mean { private double x, y, z; //constructor with three values Mean(double value1, double value2, double value3 { x = value1; y = value2; z = value3; } //constructor with three values (different type) Mean(double value1, int value2, String value3) { x = value1; y = (double)value2; z = Double.parseDouble(value3); }

}

public double findMean() { return (x + y + z) / 3; }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

153

class Mean ของเรากําหนดใหมี constructor สองตัว โดยกําหนดใหตัวแรกรับ parameter ที่เปน double ทั้งสามตัว สวน constructor ตัวทีส ่ องรับ parameter ที่เปน double int และ String ตามลําดับ ซึ่งเราไดเปลี่ยนคาที่ไมใช double ของทั้งสอง parameter ใหเปน double ภายในตัว constructor เอง class TestMean1 { public static void main(String[] args) { //create objects with diferent parameters Mean p = new Mean(10.0, 20.0, 30.0); Mean q = new Mean(10.0, 20, "40.0");

}

}

System.out.println("Mean of p is " + p.findMean()); System.out.println("Mean of q is " + q.findMean());

โปรแกรม TestMean1.java ประกาศการใช object สองตัวคือ p และ q จาก class Mean ดวย parameter ตางกันดังที่เห็น ผลลัพธที่ไดของการ run คือ Mean of p is 20.0 Mean of q is 23.0333333333333332 เชนเดียวกับโปรแกรมกอนหนานี้ ผลลัพธที่ไดแสดงถึงการเรียกใช constructor ที่ถูกตองของ Java ยังมีวิธีอื่นที่เราสามารถที่จะ overload constructor ได วิธีนี้เราจะเรียก constructor ตัวอื่นจาก constructor อีกตัว การเรียก constructor จาก constructor วิธีการเรียก constructor จาก constructor ก็ไมยาก เราเพียงแตกําหนดวิธีการเรียกใหเหมาะสม ซึ่ง Java ยอมใหมก ี ารเรียก constructor จาก constructor ผานทางคําวา this ดังตัวอยางที่ไดแสดง ดังนี้ //TestMean2.java class Mean { private double x, y, z; //constructor with one value Mean(double value) { x = value; y = 0.0; z = 0.0; } //constructor with two values Mean(double value1, double value2) { //calling constructor with one argument this(value1); y = value2; } //constructor with three values Mean(double value1, double value2, double value3) { //calling constructor with two arguments this(value1, value2); z = value3; }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

}

Objects และ Classes

154

public double findMean() { return (x + y + z) / 3; }

class TestMean2 { public static void main(String[] args) { //create objects with diferent parameters Mean m = new Mean(12.0); Mean n = new Mean(10.0, 20.0); Mean p = new Mean(10.0, 20.0, 30.0);

}

}

System.out.println("Mean of m is " + m.findMean()); System.out.println("Mean of n is " + n.findMean()); System.out.println("Mean of p is " + p.findMean());

เราไดดด ั แปลงโปรแกรมของการหาคาเฉลีย ่ ของเลขสามตัวกอนหนานี้ให มี constructor ทีเ่ รียกใช constructor ดังนี้ Mean(double value) { x = value; y = 0.0; z = 0.0; } Mean(double value1, double value2) { //calling constructor with one argument this(value1); y = value2; } Mean(double value1, double value2, double value3) { //calling constructor with two arguments this(value1, value2); z = value3; } constructor ตัวแรกกําหนดคาใหกับตัวแปรเชนเดียวกับที่ไดทําไวกอนหนานี้ สวน constructor ตัวทีส ่ อง และสามเรียกใช constructor ที่มีอยูภ  ายใน class Mean ดวยการเรียกผาน this() โดยที่ constructor ตัว ที่สองเรียก constructor ตัวแรกดวยคําสั่ง this(value1) เมื่อ Java เห็นการเรียกเชนนี้ ก็จะไปหา constructor ทีม ่ ีอยูใน class วามีตัวไหนบางที่มีเงื่อนไขตามที่ถูกเรียก ซึ่งก็เปนไปตามนั้นคือ Java ไป เรียก constructor ที่มี parameter เพียงตัวเดียวมาทําการกําหนดคาเบื้องตนใหกับ object ที่ execute constructor ตัวนี้ คือ x จะมีคา เปน value1 y และ z จะมีคาเปน 0.0 จากการกําหนด หลังจากนั้นการ กําหนดคาให y เปน value2 ก็ไดถูกกระทําภายใน constructor ตัวที่สอง constructor ตัวทีส ่ ามก็เชนเดียวกัน การเรียก constructor ที่มี parameter 2 ตัวก็เกิดขึ้น กระบวนการ เดิมที่ไดกลาวไวกอนหนานี้ก็ไดถูกกระทําขึ้น เมื่อทําเสร็จแลว การกําหนดคาใหกับตัวแปร z จึงมีขึ้น (ผลลัพธของโปรแกรม TestMean2.java ก็เหมือนกับที่เราไดกอนหนานี้) การเรียกใช constructor ที่มอ ี ยูแลวทําใหการเขียน code ที่ซ้ําซอนลดลง การเขียนโปรแกรมก็มี ประสิทธิภาพมากขึ้น

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

155

การ overload method เนื่องจากวา constructor ก็เปน method ชนิดหนึ่งดังนั้นถาเราสามารถที่จะ overload constructor ได เราก็สามารถทีจ ่ ะ overload method ไดเชนกัน เพราะฉะนั้นเราจะมาดูเรือ ่ งการ overload method ซึ่งก็ ไมแตกตางจากการ overload constructor เทาใดนัก เรามาเริ่มตนดวย method ที่แสดงผลออกทาง หนาจอ จากตัวแปรชนิดตาง ๆ ที่สงเขาไปยัง method นี้ //Overload.java class Ball { private double x, y, z; //constructor Ball() { x = y = z = 0.0; }

}

//display coordinates public void display() { System.out.println("(" + x + ", " + y + ", " + z + ")"); }

class Overload { public static void main(String[] args) { Ball ball = new Ball(); //create object

}

display(25); //display int display(350.0); //display double display("I love overloading."); //display string display('A'); //display char display(ball); //display object

//accept int as a parameter public static void display(int data) { System.out.println(data); } //accept double as a parameter public static void display(double data) { System.out.println(data); } //accept string as a parameter public static void display(String data) { System.out.println(data); } //accept char as a parameter public static void display(char data) { System.out.println(data); } //accept object as a parameter public static void display(Ball blue) { blue.display(); //calling display() from class Ball }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

156

} โปรแกรม Overload.java สราง method display() เพื่อรองรับ parameter ตาง ๆ จํานวน 5 ตัว คือ รับ int รับ double รับ string รับ char และรับ object และก็เชนเดียวกับการ overload constructor method ที่เราเขียนขึ้นตางก็มี signature ที่ไมเหมือนกัน ดังนั้น java ก็สามารถหา method ที่ถูกตองตามการ เรียกใช ผลลัพธที่ไดจากการ run โปรแกรมคือ 25 350.0 I love overloading. A (0.0, 0.0, 0.0) การใช overload นั้นมีขอดีในการเขียนโปรแกรมคือ เราไมจาํ เปนตองหาชื่ออื่น ๆ ที่เหมาะสมกับหนาที่ ของ method นั้น ๆ นอกเหนือจากที่เราไดเลือกไวแลว และการใชชื่อเดียวเพื่อรองรับ parameter หลาย ตัวทําใหผูใชไมตองคนหา method ตัวอื่น ที่ทาํ หนาที่แบบเดียวกัน ตัว Java เองก็ไดสราง method ไว มากมายที่มีการใช overload ในการสรางเพือ ่ รองรับการใชงานของ user ที่มีความหลากหลายของขอมูล ที่สงเขาไปยัง method นั้น ๆ ทําใหผใู ชไมตอ  งเสียเวลาในการคนหา method ทีต ่ ัวเองตองการใช ผูอานควรฝกการเขียนโปรแกรมดวยการใช overload method เพื่อใหเกิดความชํานาญ และเขาใจถึง วิธีการของ method overload มากยิ่งขึ้น การสราง class ภายใน class (nested class) ตัวอยางของการสรางและเรียกใช class ที่เราไดทราบถึงกอนหนานี้ เปนการสราง class ทีม ่ ีเพียง เฉพาะตัวแปร และ method อยูภายใน class เทานั้น ยังไมมีขอมูลภายใน class ที่ตัวมันเองก็เปน class เชนเดียวกัน เราจะมาดูถึงวิธีการสราง class ภายใน class อยางงาย ๆ เพื่อใหไดรับทราบวา Java ยอมให มีการสราง class ภายใน class เชนเดียวกันกับที่เราสามารถสราง method อื่น ๆ เราจะลองเขียนโปรแกรมตัวอยางแบบงาย ๆ ที่ class ซอนกันอยู //NestedClass.java class Parent { private String name; Child c = new Child("Galvin");

//create a Child object

Parent(String n) { name = n; } public void showName() { System.out.println("Parent: " + name); c.showName(); //calling Child's showName() } class Child { private String name; //create a GrandChild object GrandChild gc = new GrandChild("Jeff"); Child(String n) { name = n; } public void showName() { System.out.println("Child: " + name); gc.showName(); //calling GrandChild's showName()

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

157

} class GrandChild { private String name; GrandChild(String n) { name = n; } public void showName() { System.out.println("GrandChild: " + name); } }//class GrandChild }//class Child }//class Parent class NestedClass { public static void main(String[] args) { Parent p = new Parent("Rebecca");

}

}

p.showName();

โปรแกรม NestedClass.java สราง object จาก class Parent หนึ่งตัว แสดงขอมูลที่อยูใน class ผาน ทาง method showName() ซึ่งใหผลลัพธ ดังนี้ คือ Parent: Rebecca Child: Galvin GrandChild: Jeff class Parent ของเราไดสราง class อีก class หนึ่งที่อยูภายในชื่อ Child และ class Child ก็ไดสราง class อีก class หนึ่งชื่อ GrandChild โดยทุก class จะมี method ชื่อ showName() ซึ่งเอาไวใชในการ แสดงคาของตัวแปรของแตละ class ไปยังหนาจอ เราไดสราง object จาก class Child ภายใน class Parent ชื่อ c และเราเรียก method showName() ของ class Child จาก method showName() ของ class Parent ในทํานองเดียวกันราก็ไดสราง object จาก class GrandChild ภายใน class Child และก็ เรียก method showName() ของ class GrandChild จาก method showName() ของ class Child ดวย เพราะฉะนัน ้ ขั้นตอนของการ execute คือ Parent.showName() Æ Child.showName() Æ GrandChild.showName() เราสามารถทีจ ่ ะสราง object จาก class ที่อยูดานในผานทาง object ที่อยูดานนอก ดังเชนตัวอยางนี้ class NestedClass { public static void main(String[] args) { Parent p = new Parent("Rebecca");

}

}

p.showName(); Parent.Child newChild = p.new Child("John"); Parent.Child.GrandChild newGrandChild = newChild.new GrandChild("Jen"); newChild.showName(); newGrandChild.showName();

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

158

เราเพิ่มประโยคใหมเขากับ class NestedClass ของเราเพื่อแสดงการสราง object จาก class ที่อยูภายใน ประโยค Parent.Child newChild = p.new Child("John"); สราง object จาก class Child ผานทาง object ที่มาจาก class Parent ดวยการเรียกใช p.new Child("John") เราตองทําการสรางผานทาง object ของ class Parent เทานั้นเราไมสามารถที่จะสราง object จาก class Child ผานทาง class Parent โดยตรง เชน ประโยค Parent.Child newChild = Parent.new Child("John"); จะไมไดรับการ compile และ Java จะฟองดวย error ทันที การสราง object จาก class GrandChild ผานทาง class ที่อยูภายนอกทัง้ สองก็คลาย ๆ กัน ผลลัพธของการ run โปรแกรมที่ถูกดัดแปลงแลว คือ Parent: Rebecca Child: Galvin GrandChild: Jeff Child: John GrandChild: Jeff GrandChild: Jen เนื่องจากวาเราสราง object ของ class Child ผานทาง class Parent ดังนั้นเมื่อเรียกใช method showName() เราจึงไดผลลัพธ Child: John GrandChild: Jeff อีกครั้งหนึ่ง สวน object ที่สรางขึ้นใหมจาก class GrandChild เมื่อเรียก method showName() เราจึง ไดเพียงแต GrandChild: Jen เทานั้น ตัวอยางโปรแกรมการสราง nested class ที่เห็นเปนเพียงแคตัวอยางทีแ ่ สดงใหดูถึงการสราง nested class เทานั้น การออกแบบ nested class ตองคํานึงถึงความสัมพันธของทั้ง class ที่อยูดานนอก และ class ที่อยูดานในวามีความสัมพันธกันอยางไร ถาความสัมพันธนั้นสามารถที่จะเขียน class แยกกัน ออกมาได การออกแบบก็ควรใหเปน class ทีแ ่ ยกกันอยู เพราะจะทําใหการออกแบบทําไดงายกวา การ สรางและเรียกใช object ก็จะไมซับซอนเทาใดนัก มาถึงตอนนี้เราไดทราบถึงการสราง class การออกแบบ method และการสราง object จาก class พอสมควร ตัวอยางทีจ ่ ะแสดงใหดูตอไปเปนความพยายามทีจ ่ ะออกแบบ class Array ขึ้นมาใชงาน เพื่อที่จะแสดงใหเห็นถึงศักยภาพของการใช Java ในการเขียนโปรแกรม class MyArray ที่เราสรางขึ้นจะกําหนดใหเปน array ที่ใชเก็บ Object เพื่อใหมีความยืดหยุนในการ ทํางานกับขอมูลตาง ๆ ทั้งนีแ ้ ละทั้งนั้น class MyArray เปนเพียงแคตวั อยางตัวอยางหนึ่งเทานั้น ผูอาน สามารถที่จะทําไดมากกวาที่โปรแกรมตัวอยางนี้แสดงใหดู //MyArray.java class MyArray { Object []arr; //array of objects int maxSize; //maximum size of array int count; //number of items in array //default constructor MyArray() {

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

}

Objects และ Classes

count = 0; maxSize = 10; arr = new Object[maxSize];

159

//no item as yet //default maximum size //allocate space for arr

//constructor MyArray(int size) { count = 0; //no item as yet maxSize = size; //set maximum size arr = new Object[maxSize]; //allocate space for arr } //method to add item into arr public void add(Object item) { //expand capacity if arr is full //double the size if(count == maxSize) { //double arr's size maxSize *= 2; //create temporary array Object []temp = new Object[maxSize]; //copy items into new array: temp System.arraycopy(arr, 0, temp, 0, arr.length); //refer arr to temp arr = temp; } arr[count++] = item; //add new object into arr } //overload method add to accomodate double public void add(double item) { add(String.valueOf(item)); } //overload method add to accomodate int public void add(int item) { add(String.valueOf(item)); }

}

//return formatted output when user uses System.out.println() //10 items per line public String toString() { //create new buffer to hold data StringBuffer buffer = new StringBuffer(); for(int i = 0; i < maxSize; i++) { //append newline if this line already has 10 items if(i % 10 == 0) buffer.append("\n"); //stop appending when there is no item left (null) if(arr[i] == null) break; //append tab + item in arr buffer.append("\t" + arr[i]); } //returning an output String return new String(buffer + "\n"); }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

160

เรากําหนดใหมี constructor สองตัว โดยที่ตวั แรกเปน default constructor ที่กําหนดใหขนาดของ array มีความจุครั้งแรกไดเพียง 10 ตัว สวนตัวทีส ่ องเปน constructor ที่ผูใชสามารถกําหนดขนาดของ array ได เราไดออกแบบให array ของเราเปน array แบบยืดหยุน หรือที่เรียกวา dynamic array โดย เรากําหนดใหมก ี ารขยายขนาดของ array ใหเปนสองเทาของขนาดเดิมถามีการใสขอมูลเกินจํานวนที่ array สามารถรองรับได ใน method add() public void add(Object item) { //expand capacity if arr is full //double the size if(count == maxSize) { //double arr's size maxSize *= 2; //create temporary array Object []temp = new Object[maxSize]; //copy items into new array: temp System.arraycopy(arr, 0, temp, 0, arr.length); //refer arr to temp arr = temp; } arr[count++] = item; //add new object into arr } method add() ของเราจะตรวจสอบคาของ count (จํานวนของขอมูลที่มีอยูใ น array) กับ maxSize (ความจุสูงสุดที่สามารถเก็บขอมูลได) วาเปนคาเดียวกันหรือไม ถาเปนคาเดียวกันเราจะขยายขนาดของ array ออกเปนสองเทา ดวยการสราง array ตัวใหมชื่อ temp ที่มีความยาวเปนสองเทาของ array ตัว เดิม maxSize *= 2; Object []temp = new Object[maxSize]; หลังจากนั้นเราก็ทําการโยกยายขอมูลจาก array ตัวเกาสู array temp ดวยการใชคําสั่ง System.arraycopy(arr, 0, temp, 0, arr.length); คําสั่งนีจ ้ ะทําการยายขอมูลจาก arr เริ่มตนที่ index = 0 ไปสู temp เริ่มตนที่ index 0 จนกวาจะหมด ความยาวที่กําหนดให (arr.length) ซึ่งก็คือจํานวนของขอมูลที่อยูใ น arr ทั้งหมด เมื่อโยกยายขอมูลเสร็จแลวเราก็อางถึง array ตัวใหมดวย array ตัวเดิมของเราคือ arr ดวยคําสั่ง arr = temp; เรายังไดทําการ overload method add() ของเราเพื่อใหสามารถรองรับการเพิ่มขอมูลที่เปน double และ int เขาสู array ของเราได วิธีการแบบนี้ไมคอ  ยจะดีสักเทาไร เพราะเปนการนําเอาขอมูลทีไ ่ มใชชนิด เดียวกัน (โดยตรง) เขาไปเก็บไวใน array ซึ่งถาหากมีกระบวนการอื่น ๆ ที่เราตองการทํากับขอมูล เหลานั้น เราจะตองเสียเวลาในการตรวจสอบชนิดของขอมูลทุกตัวที่มีอยูใ น array ของเรา เราทําการ overload ดวยการใช method ของ class String คือ String.valueOf() ดังที่เห็นนี้ public void add(double item) { add(String.valueOf(item)); } เนื่องจากวา String เปน Object ชนิดหนึ่งดังนั้นการ add String เขาสู array ของเราจึงไมมีปญหาอะไร หลังจากนั้นเราไดเขียนโปรแกรมเพื่อตรวจสอบ ดังนี้

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

161

//TestMyArray.java import java.lang.Integer; class TestMyArray { public static void main(String[] args) { //create array of 10 objects MyArray array = new MyArray(10); //add 40 objects into array (randomized) int count = 0; while(count < 40) { int data = (int)(Math.random() * 100 + 1); array.add(new Integer(data)); ++count; } System.out.println(array); //display contents

}

}

array.add(45.23); array.add(88.23);

//add double

array.add(89); array.add(12); System.out.println(array);

//add int

เราก็ไดผลลัพธ ดังนี้ 9 54 3 1

76 65 91 70

9 76 54 65 3 91 1 70 45.23

20 83 87 27

86 3 72 47

98 36 3 14

12 96 12 51

27 24 7 22

35 63 46 74

41 19 96 95

31 75 11 98

20 86 83 3 87 72 27 47 88.23

98 36 3 14 89

12 96 12 51 12

27 24 7 22

35 63 46 74

41 19 96 95

31 75 11 98

ผูอานควรสังเกตถึงผลลัพธที่ไดโดยเฉพาะขอมูลในบรรทัดสุดทาย (ที่เราไดเพิ่มขอมูลที่เปน double และ int หลังจากการ display ครั้งแรก) สวนประกอบทีส ่ ําคัญอีกสวนหนึ่งที่ตองกลาวไวในที่นี้ คือ method toString() และกอนทีจ ่ ะพูดถึง method toString() เราควรดูประโยคอีกประโยคหนึ่งกอน นั่นก็คือ System.out.println(array); ประโยค System.our.println() จะรับเฉพาะขอมูลที่เปน String หรือ primitive datatype ที่เราไดพด ู ถึง กอนหนานี้ แตสิ่งที่เราสงไปใหเปน object จาก class MyArray ทําไมเราถึงทําได? เราสง Object ไปให System.out.println() ไดก็เพราะวาเราไดเขียน method toString() รองรับไว เรียบรอยแลว เมื่อไรก็ตามที่ Java เห็นขอมูลที่ไมใช String หรือ primitive datatype Java จะทําการ คนหา method toString() ถามี Java ก็จะใช method toString() นั้น แตถา ไมมีก็จะฟองดวย error ทันที เรามาดูกน ั วาเราเขียน method toString() อยางไร

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

162

public String toString() { //create new buffer to hold data StringBuffer buffer = new StringBuffer(); for(int i = 0; i < maxSize; i++) { //append newline if this line already has 10 items if(i % 10 == 0) buffer.append("\n"); //stop appending when there is no item left (null) if(arr[i] == null) break; //append tab + item in arr buffer.append("\t" + arr[i]); } //returning an output String return new String(buffer + "\n"); } ภายใน method toString() เราใช StringBuffer ในการเก็บสวนประกอบตาง ๆ ที่เราตองการสงกลับ ออกไป ซึ่งจะประกอบไปดวย

ขอมูลตาง ๆ ทีอ ่ ยูใน array (arr[i]) tab (\t) newline (\n)

เรานําขอมูลเหลานี้ไปเก็บไวใน buffer ดวยการใช method append() ทุก ๆ ครั้งที่เราไดขอมูลครบ 10 ตัวเราจะทําการ append newline เขาสู buffer ถาหากวาเราไดขยายขนาดของ array แตไมไดใสขอมูล ครบตามขนาดที่ไดขยายขึ้น เราจะยุติการนําขอมูลเขาสู buffer เนื่องจากวาขอมูลเหลานีม ้ ีคาเปน null และเราก็ไมตองการแสดงคาเหลานี้ เมื่อเราไดขอมูลทั้งหมดที่ตองการแลว เราก็สงกลับออกไป โดย สงออกไปในรูปแบบของ String (เพราะ System.out.println() ตองการ String) ดวยคําสัง่ return new String(buffer + "\n"); ผูอานสามารถนําเอาเทคนิคนี้ไปใชกับการแสดงขอมูลอื่น ๆ ผานทาง System.out.println() ไดโดยไมมี ขอจํากัดใด ๆ ทั้งสิ้น เราสามารถทีจ ่ ะสราง class เพื่อการใชงานของเราโดยไมมข ี ีดจํากัดใด ๆ ทั้งนี้ก็ตองขึ้นอยูกับลักษณะงาน นั้น ๆ วาอยูในรูปแบบไหน ความยาก งายของงานเปนอยางไร ตัวอยางการสราง array ขึ้นมาใชงานเปน เพียงตัวอยางเล็ก ๆ เพียงตัวอยางเดียวที่เราไดแสดงใหดูถงึ ขอดีของภาษา Java ยังมีสิ่งอื่น ๆ ที่ผูอาน สามารถที่จะสรางขึ้นมาสําหรับงานของตัวเองได Package Package เปนที่รวมของ class ตาง ๆ ที่ถูกเรียกใชในโปรแกรม หรือ method ตาง ๆ class ทุก ๆ ตัวของ Java ไดถูกจัดถูกเก็บอยูใน package ตาง ๆ เชน java.lang หรือ java.io การเอา class ตาง ๆ มารวมกัน ไวใน package เดียวกันทําใหการเรียกใช class ตาง ๆ เหลานี้ทําไดงายขึ้น ถาผูอานมองยอนกลับไปดู โปรแกรมตัวอยางตาง ๆ ที่เราเขียนขึ้น ก็จะเห็นการเรียกใช package เหลานีใ้ นโปรแกรมหลาย ๆ ตัว เรา จะมาดูถึงวิธีการสราง package เพื่อเก็บ class และการเรียกใช package เหลานี้ในโปรแกรมตัวอยาง การสราง package การสราง package นั้นไมยาก ขั้นตอนก็ไมซับซอนเทาไร ขัน ้ ตอนแรกที่เราตองทําก็คือ ใสคําวา package ตามดวย ชื่อของ package นั้นกอนประโยคใด ๆ ในไฟลที่เก็บ class นั้น ๆ ที่เราสรางขึ้น (ยกเวนประโยคที่เปน comment) เชน //package Shape package Shape;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

163

public class Rectangle { … … } ถาเราไมใสคาํ วา public ไวดานหนาของ class หรือ method ที่อยูใน package ที่เราสรางขึน ้ โปรแกรม หรือ class ตัวอืน ่ ๆ ที่อยูนอก package ก็ไมสามารถที่จะเรียกใช class นี้ได ยกเวน class อื่น ๆ ที่อยูใน package นี้เทานั้น package ตัวอยางของเราใชชื่อวา Sample โดยเรากําหนดให Sample ประกอบไป ดวย class One และ class Two และเราไดสราง package อีกตัวหนึ่งใน Sample ใหชื่อวา oneMore และใน package oneMore นี้เราจะเก็บ class Three ไว ดังที่เห็นจาก code ขางลางนี้ //sample package package Sample; public class One { public One() { System.out.println("This is class One in Sample package."); } } //sample package package Sample; public class Two { public Two() { System.out.println("This is class Two in Sample package."); } } //sample package package Sample.oneMore; public class Three { public Three() { System.out.println("This is class Three in Sample.oneMore package."); } } ในการ compile ไฟลทั้งสามที่ไดสรางขึ้นนี้ เราใชคําสั่ง javac -d e:\bc221Book\source ตามดวยชื่อ ไฟล เชน javac -d e:\bc221Book\source One.java เราตองใช option -d ในการ compile ไฟลทงั้ สามเพื่อบอกให Java รูถึงแฟมปลายทางที่เราตองการเก็บ class ไฟลที่เกิดขึ้นจากการ compile ในที่นี้เราจะเก็บ class ไฟลไวใน e:\bc221Book\source ภายในไฟล One.java และ Two.java เราไดใชคาํ สั่ง package Sample เปนตัวบอกถึงทีเ่ ก็บ class ไฟล และในตัวไฟล Three.java เราใชคําสั่ง package Sample.oneMore เพราะฉะนั้น class ไฟลที่เกิดขึ้นจะ ถูกเก็บไวในแฟม (directory) เหลานี้ ดังที่ไดแสดงไวในรูปทีเ่ ห็นดานลางนี้

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

164

Package ชื่อ Sample ใน e:\bc221Book\source

Package ชื่อ oneMore ใน e:\bc221Book\source\Sample

Class ไฟลท่ถ ี ูกสรางขึ้น

รูปที่ 5.7 แฟมเก็บ class file ที่เกิดขึ้นจากการ compile ดวย option -d

หลังจากนั้นเราก็สรางโปรแกรมตรวจสอบการเรียกใช package ที่เราไดสรางขึ้น โดยที่เรากําหนดใหมีการ เรียกใช class ตาง ๆ ดวยการใชคาํ สั่ง import ดังนี้ //test the package import Sample.One; import Sample.Two; import Sample.oneMore.Three; class TestPackage { public static void main(String[] args) { One object1 = new One(); Two object2 = new Two(); Three object3 = new Three(); } } หลังจากนั้นเราก็ compile โปรแกรม TestPackage.java ดวยคําสั่ง javac -classpath e:\bc221Book\source TestPackage.java โดยเราใช option –classpath ตามดวยที่อยูข  อง class ตาง ๆ ที่เราไดสรางขึ้นในการ compile และเมื่อ ทดลอง run ดูผลลัพธที่ไดคอ ื This is class One in Sample package. This is class Two in Sample package. This is class Three in Sample.oneMore package. ในการสราง package นั้น Java จะไปสรางแฟมทีม ่ ีชื่อเหมือนกับที่เรากําหนดไว ดังที่ไดเห็นในตัวอยาง และเราสามารถที่จะกําหนด sub-directory ดวยการใช . (dot) เชนที่เราไดทําไว (Sample.oneMore) และเราตองไมลืมใชคําวา public นําหนา class และ method ตาง ๆ ที่เราตองการใหโปรแกรม หรือ class หรือ method อื่น ๆ ที่อยูนอก package ใช เราไมจําเปนตอง compile ดวยการใชคาํ สั่งที่มี option –classpath ในการ compile โปรแกรมที่เรียกใช package ตาง ๆ ของ Java เพราะ Java ไดจด ั การเรื่องตาง ๆ เหลานี้ใหเราเรียบรอยแลว ถาเราใช class ตาง ๆ ที่อยูใ น package ที่สรางขึ้นบอยครั้ง หรือทุกครั้ง เราก็สามารถที่จะกําหนดให Java คนหา class ตาง ๆ เหลานี้โดยไมตองกําหนด option –d ในการ compile เราเพียงแตกําหนด classpath ไวกอนการ compile ครั้งแรกเพียงครั้งเดียว ดังนี้

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

165

set classpath=e:\bc221Book\source ถาเราไมอยากที่จะกําหนด classpath ทุกครัง้ ที่เราตอง compile เราก็กําหนด classpath ไวในไฟล autoexec.bat สําหรับ Windows รุนเกา ๆ สวน Windows รุน  ใหมเราตองกําหนด classpath ไวใน environment variables (คลาย ๆ กับการกําหนด path ของ Java ในบทที่หนึ่ง) ถาเรามี package อื่น ๆ ที่เราตองการใช เราก็ใช ; เปนตัวแบง classpath เชน set classpath=e:\bc221Book\source; c:\myOthers\Shape สรุป ในบทนี้เราไดสาํ รวจถึงวิธีการสราง class การสราง object การสราง method และการสราง method และ constructor ทีม ่ ี signature ที่แตกตางกันในการรองรับการเรียกใชดวย parameter ที่ตา งกัน การกําหนด นโยบายการเขาหาขอมูลที่อยูใ น class รวมไปถึงการสราง nested class และการสราง package โดย สรุปแลวเราไดทราบถึง 9 9 9 9 9 9 9 9 9

สวนประกอบของ class ชื่อของ class จะตองเปนชื่อเดียวกันกับๆฟลที่เก็บ class นั้นอยู การประกาศตัวแปรที่เรียกวา class variable ตองใชคําวา static นําหนา ตัวแปรที่เปน instance variable สามารถที่จะเขาหาไดผานทาง object ที่เกิดจาก class นั้น การสราง method จะตองบอกถึงสิ่งที่ตองสงกลับ ชนิดและจํานวนของ parameter (ถามี) Method ที่ประกาศใหเปน static สามารถถูกเรียกใชไดถึงแมวาจะไมมี object ใด ๆ ถูกสรางขึ้น การเขาหาขอมูลใน class มีสามแบบคือ private public และ protected (ไมนับแบบที่ไมมค ี าํ ใด ๆ นําหนา) การสราง class สามารถที่จะสรางใหอยูใน class อื่นได การสราง และ การใช package จะตองใชคาํ วา public นําหนา class หรือ method ที่ตองการให ผูอื่นที่อยูนอก package ใช

แบบฝกหัด 1. จงออกแบบ class ที่ใชเก็บขอมูลเกี่ยวกับ นักศึกษา เชน รหัส ชื่อ-นามสกุล ที่อยู และขอมูลอื่น ๆ ที่ เห็นวาเหมาะสม ใหเขียนโปรแกรมทดสอบการสราง object ตาง ๆ จาก class ที่ไดสรางขึ้นนี้ 2. จงออกแบบ class ที่ใชเก็บขอมูลที่เกี่ยวของกับน้ําหนัก เชน ตัน กิโลกรัม และ กรัม โดยใหออกแบบ ใหมี constructor ทีร่ องรับการสราง object ดวยจํานวน parameter ที่ตางกัน ชนิดของ parameter ที่ตางกัน รวมไปถึงการออกแบบ method ทีท ่ ําการบวก การลบ object ตาง ๆ ที่ไดถูกสรางขึ้น ให เขียนโปรแกรมทดสอบ 3. จาก class MyArray ทีส ่ ามารถเก็บขอมูลที่เปน object ตางชนิดกันได จากตัวอยางที่ใหไว จงเขียน method ที่สงจํานวน object ที่มีอยูใน array ใหชื่อวา getCount() และ method dataAt() ทีส ่ งคา ของขอมูล ณ ตําแหนงที่กําหนดใหกลับไปยังผูเรียก เชน ถาเรียกดวย Object obj = arr.dataAt(7); จะสงขอมูล ณ ตําแหนงที่ 7 มาใหกับตัวแปร obj ใหเขียนโปรแกรมทดสอบ method ที่เขียนขึ้น 4. จงเขียนโปรแกรมที่มี method ในการคํานวณหาพื้นที่ของวงกลมที่มี parameter ตางชนิดกัน เชน ผู เรียกใช method อาจสงขอมูลที่มีชนิดเปน int double float หรือ String ที่เปนตัวเลข เชน "234" ใหเขียนโปรแกรมตรวจสอบ method เหลานี้ 5. จงเขียนโปรแกรมทีต ่ รวจสอบการใช overloaded constructor ในการกําหนดคาใหกับ instance variable ที่มีอยูใน class นั้น ๆ ใหเขียนโปรแกรมทดสอบ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 5 เริ่มตนกับ Java

Objects และ Classes

166

6. จงออกแบบ class สําหรับเก็บขอมูลที่เกี่ยวของกับนักศึกษา เชน รหัสประจําตัว ชื่อ นามสกุล ที่อยู และขอมูลอื่น ๆ ที่จําเปน รวมไปถึง method ตาง ๆ ที่ใชในการกําหนดคา หรือประมวลผลเกรดเฉลีย ่ และ method สําหรับการแสดงผลไปยังหนาจอ 7. จงออกแบบ class สําหรับเก็บขอมูลของ วัน เดือน ป ในรูปแบบของ dd:mm:yyyy โดยกําหนดให ขอมูลนี้นําเขามาจาก keyboard ใหเขียน Method ที่ทาํ หนาที่ในการเปลี่ยนขอมูลนี้ใหอยูใ นรูปแบบ ที่ขึ้นตนดวย วัน ตามดวย วันที่ เดือน และ ป เชน วันจันทรที่ 12 สิงหาคม พ.ศ. 2546 หรือ Monday 12 August 2003 ใหเขียนโปรแกรมทดสอบ 8. จงออกแบบ class Matrix สําหรับการประมวลผลตาง ๆ เชน การบวก การลบ การคูณ และ กระบวนการอื่น ๆ ที่เกี่ยวของ ใหเขียนโปรแกรมทดสอบ 9. จงออกแบบ class ที่ใชสําหรับการคํานวณหาอายุของ user ที่ใสเขามาจาก keyboard ในรูปแบบ ของ dd/mm/yyy โดยใหผลลัพธที่หาไดอยูในรูปแบบของ จํานวนของวัน ทัง้ หมด ใหเขียนโปรแกรม ทดสอบ 10. จงออกแบบ class MyString ที่มี method สําหรับการประมวลที่เกี่ยวของกับ string ตาง ๆ เชน การ บวก string สองตัว การคนหาคําใน string การลบคําที่อยูใน string การนับจํานวนตัวอักษรที่อยูใ น string ใหเขียนโปรแกรมทดสอบ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


เราไดพูดถึงการสราง class และสวนประกอบตาง ๆ ทีส ่ ําคัญของ class รวมไปถึงการสราง method ใน บททีห ่ า สําหรับบททีห ่ กนี้เราจะสํารวจในเรื่องของการสราง class ใหมจาก class เดิมที่มีอยู การนําเอา สวนประกอบของ class เดิมมาใชใน class ใหม การถายทอดคุณสมบัติและ กระบวนการตาง ๆ จาก class เดิมสู class ใหม หลังจากจบบทนี้แลว ผูอานจะไดทราบถึงเรื่องของ o o o o o

การใช class เดิมสําหรับการสราง class ใหม (Extended class) การถายทอดคุณสมบัติ (Inheritance) คุณสมบัติ และการใชประโยชนจาก polymorphism การสราง abstract class และ abstract method การใช และ การสราง interface

การสราง class ใหมจาก class เดิมที่มีอยูแ  ลวเปนการพัฒนาโปรแกรมทีท ่ ําใหการเขียน code ใชเวลา นอย และเปนการใช code อยางคุมคาทีส ่ ุด Java ยอมใหมีการสราง class เดิมจาก class ใหมไดอยาง งาย ๆ โดยทีผ ่ ูเขียนโปรแกรมแทบจะไมตองทําอะไรมากมาย (ยกเวน code ใหมที่เขียนขึน ้ ) กอนที่จะพูด ถึงศัพทตาง ๆ ที่เกี่ยวของกับการสราง class ใหมจาก class เดิมเราจะมาดูกันถึงตัวอยางของการสราง class ใหมจาก class เดิมกอน เราจะเริ่มตนดวยการสราง class งาย ๆ class หนึ่งที่เกี่ยวกับรถทีใ่ ชเครื่องยนต (motor vehicle) โดย กําหนดใหมีขอมูลที่ไมซับซอน เชน ยี่หอ (make) รุน (model) ปที่ผลิต (year) และ จํานวนที่นั่ง (seats) พรอมทั้งกําหนดใหมี method สําหรับการเขาหาขอมูลเหลานั้น หลังจากทีไ ่ ด class MotorVehicle แลว เราก็ออกแบบ class อื่น ๆ ที่ไดรับคุณสมบัตจ ิ าก class MotorVehicle ดังที่แสดงใหเห็นคราว ๆ จาก diagram นี้ (เราจะดูโครงสรางของ class ทั้งหมดตอไป) MotorVehicle

Car

Compact

Motorcycle

OffRoad

ภาพที่ 6.1 ตัวอยางของ base-class และ derived-class

Scooter

Chopper


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

168

เราออกแบบให class MotorVehicle เปน class แมแบบ หรือที่เรียกวา parent class (หรือ base class หรือ super class) ซึ่งจะเปน class ที่อยูดานบนสุดของ class ตาง ๆ ในกลุมนี้ เรากําหนดให class MotorVehicle มี class ลูก (children) อยูสอง class คือ class Car และ class Motorcycle class ลูกทั้ง สองตางก็มี class ที่เปนลูกของมันเองอีกสอง class โดยที่ class Car มีลูกเปน class Compact และ class OffRoad สวน class Motorcycle มี class Scooter และ class Chopper เปน class ลูก เราจะ กําหนดให class ลูกไดรับคุณสมบัตจ ิ าก class แมทั้งหมด คือ ขอมูลทุกตัวที่มีอยูใน class MotorVehicle เรามาดูกันถึง ขอมูล และ method ที่เรากําหนดใหมใี น class MotorVehicle //MotorVehicle.java – Inheritance class MotorVehicle { protected String make; protected String model; protected int year; protected int seats;

//e.g. //e.g. //e.g. //e.g.

Ford, Honda Taurus, Steed 2001, 2003. 4, 2

//constructor MotorVehicle(String make, String model, int year, int seats) { this.make = make; this.model = model; this.year = year; this.seats = seats; } public String getMake() { return make; } public String getModel() { return model; } public int getYear() { return year; }

}

public int getSeats() { return seats; }

เรากําหนดใหตวั แปรที่มีอยูใ น class MotorVehicle ใชนโยบายของการเขาหาแบบ protected ซึ่งเปนการ กําหนดให class ลูกที่เกิดขึ้นจาก class MotorVehicle สามารถที่จะเรียกใชตัวแปรเหลานี้ได class อื่น ๆ ที่ไมไดมาจาก class นี้จะมองไมเห็นขอมูลเหลานี้ เรากําหนดใหมี constructor เพียงตัวเดียวสําหรับการ สราง object โดยเราเลือกใชคําสั่ง this ในการแยกแยะตัวแปรที่อยูใ น class กับตัวแปรที่เปน parameter MotorVehicle(String make, String model, int year, int seats) { this.make = make; this.model = model; this.year = year; this.seats = seats; } คําวา this เปนคําที่ Java สงวนไวสําหรับการบงบอกถึง object ที่ไดรับการกระทําดวยกระบวนการตาง ๆ ณ เวลานั้น ๆ เชนในตัวอยางประโยค this.make = make;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

169

เมื่อ Java ประมวลผล constructor ตัวนี้ Java จะทําการกําหนดคาจากตัวแปร make ที่เปน parameter ของ constructor ใหกับตัวแปร make ที่อยูใน class ซึ่งเปน copy ที่ object ตัวนี้ใชอยู เราไมจําเปนทีจ ่ ะตองใช this เปนตัวบงบอกตัวแปรเสมอไป ถาเราใชตัวแปรที่อยูใ น parameter list ที่มี ชื่อไมเหมือนกับ ตัวแปรของ class (เชนตัวอยางอื่น ๆ ที่เราไดแสดงไวในบททีห ่ า) สวน method อื่น ๆ ที่ มีอยูก็เปนเพียง method ที่สงคาของตัวแปรเหลานี้ใหกับผูเรียก สําหรับ class อื่น ๆ ที่เราไดสรางขึ้นมี ดังนี้ //Car.java - Derived from MotorVehicle class Car extends MotorVehicle { protected int doors; Car(String make, String model, int year, int seats, int doors) { super(make, model, year, seats); this.doors = doors; } public int getDoors() { return doors; } //display Car's information as string //using base class methods public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append(super.getMake() + ", " + super.getModel() + ", " + super.getYear() + ", " + " seating: " + super.getSeats() + ", " + doors + "doors."); return new String(buffer); } }

เราสราง class Car จาก class MotorVehicle ดวยการใชคําสั่ง class Car extends MotorVehicle ซึ่ง เปนคําสั่งที่ Java กําหนดใหใชถาตองการสราง class ใหมทต ี่ องการใชคุณสมบัติของ class อื่น ภายใน class Car ที่เราไดสรางขึ้นเรากําหนดใหมีตวั แปรหนึง่ ตัวที่เปนตัวกําหนดจํานวนของประตูที่รถคัน นี้มีอยู และเพื่อใหการแสดงผลไปยังหนาจอทําไดงายขึ้น เราก็สราง method toString() สําหรับการ แสดงผลของ object ที่เกิดจาก class Car ของเรา เราเรียกขอมูลที่เราไดรบ ั การถายทอดจาก class MotorVehicle ดวยการใชคําสัง่ ดังนี้ super.getMake(); เมื่อ Java เห็นการใชคําสั่งแบบนี้ Java ก็จะไปคนหา method getMake() ที่อยูใน class ที่เปน class แม หรือที่เรียกกันวา super class พรอมทั้งประมวลผลคําสั่งตาง ๆ ที่มีอยูใน method getMake() ผูอานจะเห็นวาเราไมตองประกาศตัวแปรขึ้นมาใชใหมใน class Car ของเราเลย เราสามารถเรียกใชตัว แปรเหลานีจ ้ าก class MotorVehicle ไดเลย เรามาทดสอบ class ทั้งสองดวยการสราง object จาก class Car สองตัว เชนที่เห็นในโปรแกรม TestVehicle.java นี้ //TestVehicle.java class TestVehicle { public static void main(String[] args) { //create two cars, ford and honda

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

170

Car ford = new Car("Ford", "Taurus", 2001, 5, 5); Car honda = new Car("Honda", "City", 2003, 4, 4);

}

}

//display informatin about cars System.out.println(ford); System.out.println(honda);

ผลลัพธที่เราไดจากการ run คือ Ford, Taurus, 2001, seating: 5, 5 doors. Honda, City, 2003, seating: 4, 4 doors. เราไดใชนโยบายการเขาหาแบบที่ใชคําวา protected ซึ่งเราไมไดอธิบายไวเลยกอนหนานี้ สาเหตุก็ เนื่องจากวาคําวา protected โดยสวนใหญจะใชกันในเรื่องของการถายทอดคุณสมบัติจาก class แมไปยัง class ลูก โดยกําหนดไววา class ลูกสามารถที่จะใชตัวแปร (หรือ method ที่ใชคําวา protected นําหนา) จาก class แมไดอยางไมมีเงื่อนไข แตถาเราใชคําวา private แทน class ลูกไมสามารถทีจ ่ ะเขาหาตัว แปร หรือ method เหลานี้ได ดังตัวอยางตอไปนี้ Car(String make, String model, int year, int seats, int doors) { super(make, model, year, seats); this.doors = doors; System.out.println("base class: " + super.make); } ใน class MotorVehicle เราเปลี่ยนนโยบายการเขาหาตัวแปร make ใหเปน private private String make; และเพิ่มประโยค System.out.println("base class: " + super.make); ใน constructor ของ class Car ซึ่งเปนประโยคที่พยายามเขาหาตัวแปรใน class MotorVehicle ดวยการ ใช super.make Java จะไมยอมใหเรา compile พรอมกับฟองวาเราไมสามารถเขาหาตัวแปรตัวนี้ได วิธี เดียวที่เราจะเขาหาตัวแปรเหลานี้ได ก็คือการเขาผานทาง method getMake() ที่เราไดกําหนดนโยบาย การเขาหาใหเปน public เทานั้น โดยทั่วไปเรามักจะกําหนดใหตัวแปรทีใ่ ชรวมกันใน class ลูก (ที่มีอยูใน class แม) ทั้งหลายมีนโยบาย การเขาหาที่เปนแบบ private เพื่อปองกันการใชที่ไมพึงประสงคจาก class อื่น และเราก็ควรจะกําหนดให method ที่อยูใน base class มีนโยบายการเขาหาที่เปนแบบ protected ดวยเหตุผลเชนเดียวกัน และ เหตุผลอีกอันหนึ่งก็คือ คําวา protected เมื่อมีการนํามาใชแลว class อื่น ๆ ที่อยูใน package เดียวกันก็ สามารถที่จะเขาหาตัวแปร หรือ method เหลานี้ได ดังนั้นถาตองการให class ตาง ๆ ของเราทีส ่ รางขึ้นใน ตัวอยางเปน class ที่การใชนโยบายการเขาอยางถูกตอง เราก็ตองเปลี่ยน class ของเราใหเปน ดังนี้ class MotorVehicle { private String make; private String model; private int year; private int seats;

//e.g. //e.g. //e.g. //e.g.

Ford, Honda Taurus, Steed 2001, 2003 4, 2

//constructor MotorVehicle(String make, String model, int year, int seats) { this.make = make; this.model = model; this.year = year;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

}

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

171

this.seats = seats;

protected String getMake() { return make; } protected String getModel() { return model; } protected int getYear() { return year; }

}

protected int getSeats() { return seats; }

class Car extends MotorVehicle { private int doors; Car(String make, String model, int year, int seats, int doors) { super(make, model, year, seats); this.doors = doors; } protected int getDoors() { return doors; }

}

public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append(super.getMake() + ", " + super.getModel() + ", " + super.getYear() + ", " + "seating: " + super.getSeats() + ", " + doors + " doors."); return new String(buffer); }

เราไมสามารถที่จะเปลีย ่ นนโยบายการเขาหาของ method toString() ใหเปน protected ไดก็เพราะวา Java ไดกําหนดใหการเขาหาของ method toString() เปนแบบ public ไวแลว ซึ่งเราจะไดอธิบายตอไป ในเรื่องของการ override เพื่อใหเห็นถึงความพิเศษของ การถายทอดคุณสมบัติ และเพื่อเปนการแนะนําเรื่องของการ override เรา จะสราง class Compact ขึ้นมาอีก class หนึง่ โดยกําหนดให class Compact นี้เปน class ที่ไดรับการ ถายทอดคุณสมบัติจาก class Car ดังนี้ //Compact.java Derived from Car class Compact extends Car { //constructor -using base class (Car) constructor Compact(String make, String model, int year, int seats, int doors) { super(make, model, year, seats, doors);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

172

} //override Car's toString() method //presenting Comapct car's details as string public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("Compact car: "); buffer.append(super.toString());

}

}

return new String(buffer);

class Compact ของเราเรียกใชขอมูลทุกอยางที่ class แมมใี ห ตัวแรกที่เราเรียกใชกค ็ ือ constructor ของ class Car (ซึ่ง constructor ของ class Car ก็เรียกใช constructor ของ class MotorVehicle) ตัวที่ สองที่เราเรียกใชก็คือ method toString() ของ class Car ซึ่งเราไดเพิ่มคําวา "Compact car: " ไวกอน หนาขอมูลอื่น ๆ ดวยการใช method append() ของ class StringBuffer ดังนี้ buffer.append("Compact car: "); buffer.append(super.toString()); เมื่อทดลอง run ดวยการใชคาํ สั่ง Compact honda = new Compact("Honda", "City", 2003, 4, 4); System.out.println(honda); ผลลัพธที่ได คือ Compact car: Honda, City, 2003, seating: 4, 4 doors. ซึ่งตางจากการ run กอนหนานี้ (ตอนที่เราสราง object จาก class Car) เราใชเทคนิคทีเ่ รียกวา method overriding ในการแสดงผลขอมูลของ object ที่เกิดจาก class Compact ในการ override (ซึ่งตางกับ overload ที่เราไดทํากอนหนานี้ – overload ทํากับ method ที่ อยูใน class เดียวกันและตองเปน method ทีม ่ ี parameter list ไมเหมือนกัน) method จาก class แม หรือที่เรียกวา base class นั้นเราสามารถทีจ ่ ะเขียน code ใหทํางานในลักษณะใดก็ได โดยทั่วไปการ override method ทําใหการเรียกใชงานทําไดงายขึ้น ไมสับสน เพราะ method ชื่อเดียวกันมีอยูใน class ทุกตัว แตทําหนาที่ตามที่ไดกาํ หนดไวใน method ของ class นั้น ๆ เราสามารถทีจ ่ ะ override method ที่มีอยูใน class แมไดทก ุ ตัว และ object ที่เกิดจาก class ลูก หรือที่ เรียกวา derived class นั้นเมื่อมีการเรียกใช method ที่ไดรบ ั การ override Java จะไปเรียก method ที่ อยูใน class ลูก ไมใช method ที่อยูใ น class แม จากตัวอยางของ class Compact ที่ไดกลาวไว เราไดใชทั้ง การถายทอดคุณสมบัติ และการ override method โดยเราไดรับการถายทอดในเรื่องของตัวแปร และไดใชเทคนิคการ override ในการใช method toString() Method ที่ไดรบ ั การ override ใน class ลูกนั้นไมสามารถทีจ ่ ะเปลี่ยนแปลงนโยบายของการเขาหาใหเปน อยางอื่นที่มค ี วามเขมงวดกวาได เชน ถา method ใน class แมมีนโยบายการเขาหาที่เปน public ใน class ลูกก็ไมสามารถทีจ ่ ะเปลีย ่ นใหเปน private ไดเพราะการเขาหาแบบ private นั้นเขมงวดมากกวา แตถา ใน class แมนโยบายเปน private เราสามารถทีจ ่ ะเปลีย ่ นใหเปน public ได พูดงาย ๆ ก็คือวา เรา เพิ่มความเขมงวดนโยบายการเขาหาใน class ลูกไมได แตลดลงได เรามาลองดูตัวอยางของการถายทอดคุณสมบัติกันอีกสักตัวอยางหนึ่ง สมมติวาเรามี class ตาง ๆ ดังที่ แสดงใน diagram นี้

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

173

Shapes

Polygons

Triangle

Rectangle

Circle

Square

ภาพที่ 6.2 ตัวอยาง class ที่เกี่ยวของกับ shape ตาง ๆ

โดยกําหนดใหการถายทอดคุณสมบัติเปนไปดังที่เห็นใน diagram คือ Shapes เปน base class Polygons และ Circle เปน class ลูกของ Shapes สวน Triangle Rectangle และ Square เกิดมาจาก class Polygons ในทุก ๆ class เรากําหนดใหมี method what() เพียง method เดียว ดังทีแ ่ สดงไวใน code ที่เห็นนี้ //Shapes.java - Base class for all shapes class Shapes { //self info. protected String what() { return "I am a shape"; } //Polygons.java – Polygon class Polygons extends Shapes { //self info. protected String what() { return "I am a polygon."; } } //Circle.java - sub-class of Shapes class Circle extends Shapes { //self info protected String what() { return "I am a circle."; } } //Triangle.java - sub-class of Polygons class Triangle extends Polygons { //self info. protected String what() { return "I am a triangle."; } } //Square.java - sub-class of Polygons

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

174

class Square extends Polygons { //self info. protected String what() { return "I am a square."; } } //Rectangle.java - sub-class of Polygons class Rectangle extends Polygons { //self info. protected String what() { return "I am a rectangle."; } } เราเขียนกําหนดใหโปรแกรมตรวจสอบเปนดังนี้ //TestShapes.java - driver program class TestShapes { public static void main(String[] args) { //creating different shape objects from Shapes Shapes shape = new Shapes(); Shapes poly = new Polygons(); Shapes sq = new Square(); Shapes cir = new Circle();

}

//display info. about particular shapes System.out.println(shape.what()); System.out.println(sq.what()); System.out.println(cir.what()); System.out.println(poly.what());

}

ในโปรแกรมตรวจสอบเราไดสราง object สี่ตวั จาก class Shapes แตทําการกําหนดการสรางผานทาง constructor ของ class นั้น ๆ ที่เราตองการสราง เชน Shapes sq = new Square(); ถามองดูอยางผิวเผินจะเห็นวาการประกาศแบบนี้ไมนาที่จะทําได เนื่องจากวาเรากําหนดให sq เปน object ที่มส ี ถานะเปน Shapes แตกลับไปเรียก constructor ของ Square แต Java ยอมใหการสราง object แบบนี้เกิดขึ้นไดก็เพราะวา Square เปน class ที่เกิดมาจาก class Shapes (พูดงาย ๆ ก็คือ Circle เปน Shapes แบบหนึ่ง) และภายใน class Shapes เรากําหนดใหมี method what() อยู ดังนั้น class ลูก ที่เกิดมาก็สามารถที่จะเขาหา method นี้ไดแต ภายในตัว class ลูกทั้งหมดก็มี method what() อยูดังนั้น การเรียก method what() ขึ้นมาใชจึงเปนการเรียก method ที่มีอยูภ  ายใน class ลูก (overriding) ดังที่ แสดงใหเห็นจากผลลัพธนี้ I I I I

am am am am

a a a a

shape square. circle. polygon.

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

175

Polymorphism (ความมีรป ู แบบทีห ่ ลากหลาย) การทํางานในลักษณะที่ไดกลาวมานั้นเราเรียกวา late binding หรือที่เรียกกันมากมายในหนังสือหลาย ๆ เลมวา polymorphism ซึ่งหมายถึงความเปลีย ่ นแปลงรูปแบบตามสภาพของ object ที่ไดถูกสรางขึ้น หรือ ที่เปนอยู คําวา late binding หมายถึงเวลาที่ compiler จัดสรรหนวยความจําใหกับตัวแปรในขณะที่ โปรแกรมกําลังถูก execute (run อยู) ไมใชในขณะที่กําลัง compile โปรแกรม Polymorphism ทําไดเฉพาะ method เทานั้นเราไมสามารถจะใชวิธีการแบบนี้กับตัวแปรที่อยูใน class ได การเขาหาตัวแปรจะตองทําผานทาง object ที่เกิดจาก class นั้น ๆ เทานั้น สมมติวาเราตองการที่จะเขียน method ที่คํานวณหาเสนรอบวงของ object ตาง ๆ ทีส ่ รางขึ้นมาจาก class Shapes เราก็อาจทําไดดวยการเขียน method ลงไปใน class นั้น ๆ (ที่ถูกสรางมาจาก class แม) แตการกระทําดังกลาวคงไมคอยดีเทาไรนัก ถาเราไมรูวา object ที่เราตองการสรางขึ้นมานัน ้ รูปรางหนาตา เปนอยางไร และคงจะไมคอยเขาทาเทาไรนักที่จะหาเสนรอบวงของ shape ที่เรายังไมรูวา เปน shape อะไร แต Java เอื้อโอกาสใหเราสามารถที่จะประกาศ (declare) method ใน class แมแตไปกําหนด หนาที่ (define) ใน class ลูก วิธีการดังกลาวเราเรียกวา การสราง abstract class Abstract class เปน class ที่มก ี ารประกาศ method ใน class แม แตไมมีการกําหนดหนาที่ใด ๆ เรื่อง ของการกําหนดหนาที่จะเปนภาระของ class ลูก ดังเชน ตัวอยางตอไปนี้ //Shapes.java - Base class for all shapes public abstract class Shapes { private String iAm; Shapes(String whatIam) { iAm = new String(whatIam); } //self info. public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("I am a " + iAm); return new String(buffer); }

}

//dummy method - implementation is done in derived classes //to calculate a perimeter of a shape public abstract double perimeter();

เราเปลี่ยนแปลง class Shapes ของเราใหเปน abstract class พรอมทั้งประกาศ method perimeter() ที่ ไมมี code ใด ๆ อยูเลย หลังจากนั้นเราก็สราง class อื่น ๆ ที่ไดรับการถายทอดคุณสมบัตจ ิ าก class Shapes ดังนี้ //Polygons.java – Polygon public abstract class Polygons extends Shapes { //constructor Polygons(String type) { super(type); } //self info. public String toString() { return super.toString();

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

176

}

}

//dummy method to be implemented by derived classes public abstract double perimeter();

//Triangle.java - sub-class of Polygons public class Triangle extends Polygons { private double side1, side2, side3; //constructor Triangle(String type, double side1, double side2, double side3) { super(type); //calling base-class constructor this.side1 = side1; this.side2 = side2; this.side3 = side3; } //self info. public String toString() { return super.toString(); }

}

//calculating a perimeter of this triangle public double perimeter() { return side1 + side2+ side3; }

//Circle.java - sub-class of Shapes public class Circle extends Shapes { private double radius; //constructor Circle(String type, double radius) { super(type); this.radius = radius; } //self info public String toString() { return super.toString(); }

}

//calculating a perimeter of this circle public double perimeter() { return 2.0 * Math.PI * radius; }

//Square.java - sub-class of Polygons public class Square extends Polygons { double side; //constructor

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

177

Square(String type, double side) { super(type); this.side = side; } //self info. public String toString() { return super.toString(); }

}

//calculating a perimeter of this square public double perimeter() { return side * 4; }

หลังจากที่เราไดสราง class Polygons class Circle class Triangle และ class Square พรอมทั้งกําหนด หนาที่ของ method perimeter() ใน class Circle class Triangle และ class Square เรียบรอยแลวเราก็ เขียนโปรแกรมเพื่อตรวจสอบวา method ของเราใชงานไดถก ู ตองหรือไม ดังนี้ //TestShapes.java - driver program class TestShapes { public static void main(String[] args) { Shapes cir, tri; Polygons sq; //instantiate shapes sq = new Square("square", 4.0); cir = new Circle("circle", 2.0); tri = new Triangle("triangle", 3.0, 4.0, 5.0);

}

}

//display info. about particular shapes System.out.println(sq + " with a perimeter of: " + sq.perimeter()); System.out.println(cir + " with a perimeter of: " + cir.perimeter()); System.out.println(tri + " with a perimeter of: " + tri.perimeter());

ในโปรแกรม TestShapes.java เราประกาศตัวแปร cir และ tri จาก class Shapes ตัวแปร sq จาก class Polygons สาเหตุที่เราประกาศตัวแปรแทนการสราง object ก็เพราะวา Java ไมยอมใหเราทํา เนื่องจากวา class Shapes และ class Polygons เปน class ที่ถูกกําหนดใหเปน abstract class แตเรา สามารถที่จะใชตัวแปรทั้งสามในการสราง object (instantiation) จาก class Circle class Square และ class Triangle ได ประโยคในการสราง object ทัง้ สาม sq = new Square("square", 4.0); cir = new Circle("circle", 2.0); tri = new Triangle("triangle", 3.0, 4.0, 5.0); อาจดูแปลกไปจากการสราง object ที่เราไดเคยทํามา แตเราสามารถทําไดก็เพราะวา class Shapes เปน base class ของ class ทั้งหมด สวน class Polygons ก็เปน base class ของ class Square และ class

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

178

Triangle การสราง object ทั้งสามจึงสามารถทําได พูดงาย ๆ ก็คือวา ทั้ง sq cir และ tri ตางก็เปน shape ทั้งนั้น (e.g. a square is a shape, a circle is a shape, a triangle is a shape etc.) ผลลัพธที่เราไดจากการ run คือ I am a square with a perimeter of: 16.0 I am a circle with a perimeter of: 12.566370614359172 I am a triangle with a perimeter of: 12.0 Polymorphism มีประโยชนมากในการกําหนดหนาที่ของ method ที่ object ตาง ๆ ใชรว มกัน ซึ่งหนาที่ ตาง ๆ เหลานี้จะขึ้นอยูกับคุณลักษณะของ object ที่เกิดจาก class นั้น ๆ ดังที่เราไดแสดงใหดูในการหา เสนรอบวงของรูปทรงตาง ๆ หากเราตองการเราก็สามารถทีจ ่ ะสราง array ในการเก็บ shape ตาง ๆ เหลานี้ได ดังตัวอยางทีแ ่ สดงใหเห็นนี้ //TestShapes.java - driver program class TestShapes { public static void main(String[] args) { Shapes []shapes = new Shapes[5]; //instantiate 5 shapes for(int i = 0; i < 5; i++) shapes[i] = randomShape(); //display info. about particular shapes for(int i = 0; i < 5; i++) { System.out.print(shapes[i] + " with a perimeter of: "); System.out.println(shapes[i].perimeter()); }

}

}

public static Shapes randomShape() { switch((int)(Math.random() * 3)) { default: case 0: return new Circle("circle", Math.random() * 12.0); case 1: return new Square("square", Math.random() * 10.5); case 2: return new Triangle("triangle", 2.5, 4.0, 5.5); } }

เราเลือกที่จะใหการสรางรูปทรงตาง ๆ เกิดแบบ random ดังนั้นเราจึงเขียน method randomShape() ขึ้นมาใชสําหรับการสรางรูปทรงที่ไมมีขอกําหนดที่ตายตัว รูปทรงที่เกิดขึ้นจะถูกกําหนดโดย method random() ของ class Math ผลลัพธที่ไดจากการ run คือ I I I I I

am am am am am

a a a a a

square with a triangle with circle with a triangle with circle with a

perimeter of: 15.282560130191253 a perimeter of: 12.0 perimeter of: 0.209235603993188 a perimeter of: 12.0 perimeter of: 7.8292546239806695

หากเราอยากรูว า object ทีส ่ รางขึ้นมานั้นเกิดจาก class อะไรเราก็สามารถหาไดจากการใช method getClass() และ method getName() ที่มีอยูใ น class Class ของ Java เชนถาเราตองการรูวา object ที่ shapes[0] เก็บไวเกิดมาจาก class อะไรเราก็ใชคําสั่งดังนี้

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

179

Class object = shapes[0].getClass(); System.out.println(object.getName()); ถาเราอยากรูวา object ตัวนี้มี class แมหรือไมเราก็ใช method getSuperclass() เชน Class shape = object.getSuperclass(); System.out.println(shape.getName()); ยังมี method ใน class Class อีกหลายตัวที่เราสามารถนํามาใชได แตโดยสวนใหญแลว เราแทบที่จะไม ตองใช method เหลานี้ในการพัฒนาโปรแกรมทัว่ ไปเลย เพราะ method เหลานี้จะใหขอมูลที่เกี่ยวกับ class ที่ผูใช (หรือ ของ Java) สรางขึ้นมาเทานั้นเอง การสงและรับ object ตัวอยางตอไปนี้เปนการสง object เขาไปใน method พรอมกับการสง object กลับดวยการเปลี่ยนแปลง บางอยาง สมมติวาเราตองการสราง วงกลมจาก สี่เหลี่ยมดานเทาที่มีอยูแลว เราก็อาจเขียน method ที่ ทําหนาที่นใี้ หเรา ดังนี้ //SquareToCircle.java - Passing and returning object to/from method class SquareToCircle { public static void main(String []args) { Shapes square; //a square object Shapes circle; //a circle object //creating a square with side = 3 square = new Square("square", 3.0); System.out.println(square + " with an area of " + square.area());

}

//creating a circle from a square circle = SqToCir(square); System.out.println(circle + " with an area of " + circle.area());

//method to convert a square to a circle public static Shapes SqToCir(Shapes square) { //finding a radius from an area of a square double SqArea = square.area(); double radius = Math.sqrt(SqArea / Math.PI); //instantiating a circle Circle circle = new Circle("circle", radius);

}

}

return circle;

เพื่อใหการทํางานของเราประสพผลสําเร็จ เราไดเพิ่ม abstract method area() ใน class Shapes และ class Polygons และทําการกําหนดหนาที่ของ method area() ใน class Square และ class Circle ซึ่ง เปนการคํานวณหาพื้นที่ของรูปทรงที่ไดถูกสรางขึ้น ใน class Shapes เรากําหนด ดังนี้ (ใน class Polygons ก็ทาํ แบบเดียวกัน) public abstract class Shapes { …

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

180

… //code อื่น ๆ เหมือนเดิม … …

}

public abstract double perimeter(); public abstract double area();

ใน class Circle เรากําหนด code ของ method area() ดังนี้ //calculate area of this circle public double area() { return Math.PI * radius * radius; } และใน class Square เรากําหนด code ของ method area() ดังนี้ //calculate area of this square public double area() { return side * side; } ในตัวโปรแกรมของเรา เราสราง object สองตัวคือ square และ circle โดยกําหนดให square มีความ ยาวของดานแตละดานเทากับ 3.0 หลังจากที่แสดงขอมูลของ square เรียบรอยแลวเราก็สง square ไป ให method SqToCir() ซึ่งเปน method ที่ทาํ การเปลี่ยน square ใหเปน circle โดยกําหนดใหทั้งสอง object มีพื้นที่เทากัน public static Shapes SqToCir(Shapes square) { //finding a radius from an area of a square double SqArea = square.area(); double radius = Math.sqrt(SqArea / Math.PI); //instantiating a circle Circle circle = new Circle("circle", radius); }

return circle;

เราเริ่มตนดวยการหาพื้นที่ของ square ทีส ่ งเขามา หลังจากนั้นเราก็หารัศมีของวงกลมที่เราตองการสราง จากพื้นที่ ที่หาได เมื่อไดแลวเราก็สราง circle ดวยรัศมีนี้ เสร็จแลวจึงสงวงกลมที่ไดนี้กลับไป ผลลัพธที่เราไดจากการ run โปรแกรมของเราคือ I am a square with an area of 9.0 I am a circle with an area of 9.0 ขอดีของการกําหนดให base class เปน abstract class นั้น ก็คือ เราไมตองกําหนดหนาทีข ่ อง method ใน class แม เพราะวาเราอาจไมรูขอมูลทั้งหมดที่ method ตองการใช ดังเชน method perimeter() และ method area() เนื่องจากวาเรายังไมรูวา shape ที่มีอยูเปน object ชนิดอะไร ขอมูลเปนอยางไร แตเรารู ขอมูลทั้งหมดที่ Circle และ Square ตองการใชในการคํานวณหาเสนรอบวง และพื้นทีจ ่ าก การสราง object ของ class ทั้งสอง

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

181

การสราง Interface จากเทคนิคการใช polymorphism ในตัวอยางกอนหนานี้ เราตองกําหนดใหมี method ใน class แม และ ไปกําหนดหนาที่ของ method เหลานี้ใน class ลูก ซึ่งเปนการสราง class ในลักษณะที่ซ้ําซอนพอสมควร ถาเราตองคุณสมบัติของ polymorphism ใน class ที่เกิดจาก class แมนี้ เราก็ไมจําเปนทีจ ่ ะตองสราง class แมขึ้นมา แตไปสราง interface ขึ้นมาแทน Interface เปนที่รวบรวมคาคงที่ และ abstract method ตาง ๆ ที่จะตองมีการเรียกใชใน class อื่น ๆ ที่ เรียก interface นี้ไปใช การสราง interface ก็ไมยาก แทนที่เราจะใชคําวา class เราก็ใชคําวา interface แทน เราจะใช class ตาง ๆ ทีเ่ ราไดสรางไวกอ  นหนานี้ในเรื่องของรูปทรงตาง ๆ เปนตัวอยาง และเรา จะตองทําการเปลี่ยนแปลง class ตาง ๆ ดังนี้ ใน class Shapes และ class Polygons เราจะตัดเอา abstract method perimeter() และ area() ออก พรอมกับเปลี่ยนการประกาศ class Shapes ใหเปนดังนี้ public abstract class Shapes implements Calculate { private String iAm; Shapes(String whatIam) { iAm = new String(whatIam); }

}

//self info. public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("I am a " + iAm); return new String(buffer); }

เราเพิ่มคําวา implements Calculate เขาสูด  านหลังสุดของ class Shapes โดยมีเงื่อนไขวาเราตองมี interface ชื่อ Calculate อยูแลว การสราง interface ก็ทําไดไมยาก เราเพียงแตกําหนดให Calculate เปนชื่อของ interface ที่เราตองการใช พรอมทั้งกําหนดใหมี method ตาง ๆ ที่เราตองการทีจ ่ ะใหมีใน class อื่น ๆ เชน //interface for Shapes public interface Calculate { double perimeter(); double area(); } ในการเขียน Method ที่อยูใน interface นั้นเราไมจําเปนที่จะตองกําหนดนโยบายของการเขาหา การ กําหนดนโยบายจะตองทําใน class ที่เรียกใช (implement) interface นี้ class อื่น ๆ ที่เหลืออยูก็ไมมีการเปลี่ยนแปลงอะไรมากมาย ยกเวน การคํานวณหาพื้นที่ของรูปทรงตาง ๆ ใน class Triangle เราเพิ่ม method //calculating an area of this triangle //using Huron's formula public double area() { double s = perimeter() / 2.0; double area = Math.sqrt((s * (s-side1) * (s-side2) * (s-side3))); }

return area;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

182

ใน class Circle เราเพิ่ม method //calculate area of this circle public double area() { return Math.PI * radius * radius; } ใน class Square เราเพิ่ม method //calculate area of this square public double area() { return side * side; } หลังจากที่เปลีย ่ นแปลง code บางสวนในโปรแกรมทดสอบ ดังนี้ //TestShapes.java - driver program import java.text.DecimalFormat; class TestShapes { public static void main(String[] args) { Shapes []shapes = new Shapes[5]; //instantiate 5 shapes for(int i = 0; i < 5; i++) shapes[i] = randomShape(); //display info. about particular shapes DecimalFormat f = new DecimalFormat("0.00"); for(int i = 0; i < 5; i++) { System.out.print(shapes[i] + " perimeter = "); System.out.print(f.format(shapes[i].perimeter())); System.out.println(" area = " + f.format(shapes[i].area())); }

}

}

public static Shapes randomShape() { switch((int)(Math.random() * 3)) { default: case 0: return new Circle("circle", Math.random() * 12.0); case 1: return new Square("square", Math.random() * 10.0); case 2: return new Triangle("triangle", 4.0, 5.0, 6.0); } }

ผลลัพธที่ไดคอ ื I I I I I

am am am am am

a a a a a

triangle perimeter square perimeter = circle perimeter = triangle perimeter circle perimeter =

= 15.0 area = 9.90 10.32 area = 6066 45.32 area = 163.46 = 15.00 area = 9.92 6.76 area = 3.64

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

183

เนื่องจากวาเราไดทําการเรียกใช interface Calculate ใน class แม ดังนั้นเราไมจําเปนที่จะตองเรียกใช interface Calculate ใน class ลูกเพราะ class ลูกเหลานี้ไดรับการถายทอดคุณสมบัติจาก class แม เรียบรอยแลว เหตุผลอีกอยางหนึ่งที่เรากําหนดให class Shapes มีการ implements Calculate ก็คือ เรา ไมตองการเปลีย ่ นแปลง code ที่เราไดเขียนขึ้นกอนหนานี้มากมายนัก เรามาลองดูตัวอยางของการใช interface ที่ Java มีใหสักตัวอยางหนึ่ง โดยเราจะเรียกใช interface ActionListener ในการตรวจจับเหตุการณที่จะเกิดขึ้นจากตัวโปรแกรม ตัวอยางนี้อาจมีขอมูลที่เรายังไมได พูดถึงมากพอสมควร แตประเด็นหลักทีต ่ องการแสดงก็คือการเรียกใช interface เราจะปรับปรุงโปรแกรม Interests.java ที่เราไดเขียนขึ้นในบทที่สาม ซึ่งเปนโปรแกรมสําหรับการคํานวณหาดอกเบี้ยทบตน เราจะ สราง class ขึ้นใหมดังนี้ class Account ใชเปนการเก็บ balance คํานวณดอกเบี้ย แสดงผล class นี้เรียกใช interface BankRate class Timer เปน class ที่มีอยูใน Java ใชสาํ หรับการกระทําที่ตองใชเวลา class Interests1 เปนโปรแกรมทดสอบสวนตาง ๆ ที่เราสรางขึ้น interface BankRate ใชเก็บคาคงที่ RATE ทีใ่ ชในการคํานวณหาดอกเบี้ย interface ActionListener ใชในการตรวจสอบเหตุการณที่เกิดจากผูใ ชโปรแกรม เชน ออกจากโปรแกรม เรากําหนดใหความสัมพันธของ class เปนไปตาม diagram ที่เห็นนี้ Account

GetInterest

BankRate

ActionListener

interface

Timer

ภาพที่ 6.2 การเรียกใช interface

เราเริ่มตนดวย interface BankRate และ class Account //interface for bank rate public interface BankRate { double RATE = 5.0; } //Account.java public class Account implements BankRate { private double balance; //constructor - initializing balance Account(double balance) { this.balance = balance; } //method to get balance protected double getBalance() { return balance; } //method to deposit

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

184

protected void deposit(double amount) { balance += amount; } //method to calculate interest protected double interest() { return balance * RATE / 100.0; }

}

//method to display info. about this account public String toString() { return "Balance = " + getBalance(); }

เราเขียน class Account อยางงาย ๆ โดยกําหนดใหมี method สําหรับการกําหนด balance การ คํานวณหาดอกเบี้ย และการแสดงผลผานทาง method toString() ตอไปเราจะมาดู class Interests1 ซึ่ง เปนโปรแกรมทดสอบการใชงานของ class และ interface //Interests1.java import import import import

java.awt.event.ActionEvent; java.awt.event.ActionListener; javax.swing.JOptionPane; javax.swing.Timer;

class Interests1 { public static void main(String[] args) { //create account with initial balance of 1000 final Account acc = new Account(1000); //inner class performing interest calculation //and listening to event from user //stop performing when user hit stop button in //the dialog window class GetInterest implements ActionListener { public void actionPerformed(ActionEvent event) { double ints = acc.interest(); acc.deposit(ints); System.out.println(acc); } } //create object from class GetInterest GetInterest intsPeek = new GetInterest(); //set performing time interval to one second final int DELAY = 1000; //calling actionPerformed() every 1000 milliseconds Timer t = new Timer(DELAY, intsPeek); //start the timer t.start();

}

//display dialog window - stop performing and exit //program when user hit the button JOptionPane.showMessageDialog(null, "Stop?"); System.exit(0);

}

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

185

ในโปรแกรม Interests1.java เราสราง object acc จาก class Account ดวยคา balance เริ่มตนที่ 1000 ภายใน method main() เราสราง class GetInterest ที่เรียกใช interface ActionListener ของ Java ซึ่ง จะคอยตรวจสอบเหตุการณ (event) ที่อาจเกิดขึ้นจาก user พรอมทั้งการคํานวณหาดอกเบี้ย method actionPerformed() จะถูกเรียกโดย object intsPeek จาก class Timer ดวยคา delay 1 วินาที ดวยประโยคนี้ Timer t = new Timer(DELAY, intsPeek); แตกระบวนการทั้งหมดจะเริม ่ ไดดวยการเรียก method start() ของ class Timer ดังนี้ t.start() โปรแกรมของเราจะคํานวณหาดอกเบี้ยไปจนกวา user จะกดปุม OK ที่แสดงไวใน dialog window ที่ ปรากฏอยูใ นหนาจอ ซึ่ง dialog window นี้ถูกสรางขึ้นมาดวยคําสั่ง JOptionPane.showMessageDialog(null, "Stop?"); ซึ่งมีหนาตาดังนี้

เมื่อ user กดปุม  OK เราก็จะยุติโปรแกรม และออกจากระบบดวยคําสั่ง System.exit(0); ตัวอยางผลลัพธที่ไดจากการ run โปรแกรมในชวงเวลาหนึ่ง กอนการกดปุม คือ Balance Balance Balance Balance Balance Balance Balance Balance Balance Balance Balance Balance Balance Balance

= = = = = = = = = = = = = =

1050.0 1102.5 1157.625 1215.50625 1276.2815624999998 1340.0956406249998 1407.1004226562497 1477.4554437890622 1551.3282159785153 1628.894626777441 1710.3393581163132 1795.8563260221288 1885.649142323235 1979.931599439397

เราตองการที่จะแสดงใหเห็นถึงการใช interface ทั้งที่มีอยูใน Java และที่เขียนขึ้นเอง สวนการใช สวนประกอบอื่น ๆ ที่ Java มีใหเปนเพียงสิ่งที่ผูอานจะไดสม ั ผัสในโอกาสตอไป เรามีทางเลือกสองทางในการสราง และกําหนดหนาที่ของ method ดังที่เราไดพูดไว คือ 1. กําหนดให class แมเปน abstract class พรอมทั้งกําหนดใหมี ชื่อของ method ทีต ่ องการ การ กําหนดหนาที่ของ method จะเปนภาระของ class ลูกเอง

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

186

2. กําหนดให class เรียกใช interface ที่มีการกําหนดชื่อของ method และ class ตองกําหนดหนาที่ ของ method นั้นเอง สรุป เราไดพูดถึงการสราง class ใหมจาก class ที่มีอยูกอนแลว การถายทอดคุณสมบัติจาก class แมสู class ลูก การ override method การใช polymorphism การสรางและใช interface โดยสรุปแลวสิ่งสําคัญที่ เราไดพูดไวคือ 9

9

9 9 9 9 9 9

เราสามารถสราง class ใหมจาก class ที่มีอยูก  อนแลวดวยการใชคําวา extends ซึ่ง class ที่เรา extends มานั้นเราเรียกวา base class หรือ parent สวน class ที่เราสรางขึ้นใหมเราเรียกวา sub class หรือ child เราสราง abstract class ดวยการใชคําวา abstract ซึ่งภายใน class ที่เปน abstract class นั้นจะมี method ประกาศอยู แตหนาที่ของ method ยังไมไดถูกกําหนด การกําหนดจะทําใน class ลูกเดทา นั้น และเราไมสามารถที่จะสราง object จาก abstract class ได sub class ไมไดรับการถายทอด constructor ของ super class ถาเรากําหนดนโยบายการเขาหาของ method หรือตัวแปรใหเปน private ใน class แม class ลูกจะ ไมสามารถเขาหาตัวแปร หรือ method ได ตัวแปรที่ประกาศจาก class แมสามารถที่จะใชเปนตัวชี้ไปยัง object ของ class ลูกได ซึ่งทําใหการ เรียกใช method ที่อยูใน class ลูกเปนไปได abstract class เปน class ที่ไมตองกําหนดหนาที่ให method ทุก ๆ ตัวใน class interface ประกอบไปดวย คาคงที่ abstract method และ inner class class ที่ไมกําหนดหนาที่ใหกับ method ทุกตัวที่ตวั มันเองตองใช interface จะตองประกาศใหเปน abstract class

แบบฝกหัด 1. จากขอมูลที่ใหเปนคูในแตละขอ จงแสดงถึงความสัมพันธวาสวนไหนเปน super class และสวนไหน เปน sub class ผูจัดการ นักศึกษา คน อาจารย สามี พอ

ลูกจาง อาจารย นักศึกษา บุคลากร ภรรยา ลูก

2. สมมติวา class RumRaisin extends มาจาก class Icecream จงหาวาประโยคใดตอไปนี้เปน ประโยคที่ Java ยอมรับ RumRaisin scoop1 = new RumRaisin(); Icecream scoop2 = new Icecream; scoop2 = scoop1; scoop1 = scoop2; scoop2 = new RumRaisin(); scoop1 = new Icecream(); 3. จงวาด diagram ที่แสดงถึงความสัมพันธของการถายทอดคุณสมบัติของ class ที่ใหนี้ บุคลากร ผูจัดการ นักศึกษา อาจารย หองเรียน อุปกรณประกอยการเรียน

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 6 เริ่มตนกับ Java

การสราง class ใหมจาก class เดิม และ การถายทอดคุณสมบัติ

187

รองอธิการฝายวิชาการ รองอธิการฝายบริหาร บรรณารักษ เจาหนาที่การเงิน หัวหนาฝายการเงิน 4. เราไดพูดถึงการใช method clone() ในบททีเ่ ราพูดถึงเรื่อง array จง override method clone() เพื่อทําการสราง object ใหมจาก class Shapes ที่ไดกลาวไวในบทนี้ 5. จงเพิ่ม method withdraw() ที่ทาํ หนาที่ในการถอนเงินออกจากบัญชี ของ class Account ที่ได กลาวไวในบทนี้ ใหเขียนโปรแกรมทดสอบ 6. จาก class Shapes ในบทนี้ class ที่ไมไดพูดถึงและไมมีการกําหนดหนาที่ใด ๆ เลย คือ class Rectangle จงเขียน code ที่ทาํ ให class Rectangle นี้สมบรูณ 7. จงออกแบบ class Student ที่เก็บขอมูลของนักศึกษาวิทยาลัยแหงหนึ่ง โดยใหมี sub class ที่มีทั้ง นักศึกษาระดับปริญญาตรี และระดับปริญญาโท รวมไปถึงนักศึกษาภาคพิเศษ พรอมทั้งเขียน method ในการกําหนด และเขาหาขอมูลเหลานี้ กําหนดใหมี method toString() ในทุก class สําหรับการแสดงขอมูลของ object ที่เกิดจาก class นั้น ๆ ใหเขียนโปรแกรมทดสอบ 8. จงออกแบบ class Employee ที่มี sub class เปน TempEmployee และ RegularEmployee โดย กําหนดใหลูกจางทุกคนมี ชื่อ และอัตราจางงานที่คด ิ เปนจํานวน บาท ตอชัว่ โมง จงเขียน method ที่ ทําการคํานวณหาคาจางของลูกจางทุกคน โดยกําหนดใหการคิดคาจางของ TempEmployee ขึ้นอยู กับจํานวนชั่วโมงทีท ่ ํา หากทําเกิน 40 ชั่วโมงใหคด ิ คาจางเพิ่มเปน หนึ่งเทาครึ่งของอัตราจางประจํา ของจํานวนชั่วโมงทีท ่ ําเกิน สวนลูกจางประจํา (RegularEmployee) จะไดคา จางตามอัตราที่ไดตกลง ไวลวงหนาโดยไมคํานึงถึงจํานวนชั่วโมงของงานทีท ่ ํา จงใชเทคนิคของ polymorphism ในการ ออกแบบ ใหเขียนโปรแกรมทดสอบ * class Employee ควรเปน abstract class 9. จงปรับปรุง class Shapes หรือ sub class ทีม ่ าจาก Shapes ใหมี method ในการสราง object จาก class หนึ่งใหเปน object จากอีก class หนึ่ง ดังเชนทีท ่ ําเปนตัวอยางในการสราง object Circle จาก Square จงเขียนโปรแกรมทดสอบ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


ในบทที่เจ็ดนี้เราจะพูดถึงการใช และการออกแบบ exception หรือที่เรียกวาการควบคุมและดักจับ error ที่อาจเกิดขึ้นในการ compile และ run โปรแกรม หลังจากจบบทนี้แลว ผูอานจะไดทราบถึง o o o o

ความหมายของ exception วิธีการใชและควบคุม exception การใช throws และ try การออกแบบ และใช exception ที่เขียนขึ้นเอง

ในภาษา Java นั้น exception เปนการบอกถึงสิ่งผิดปรกติที่เกิดขึ้นในโปรแกรม ซึ่งอาจเปน error หรือ เหตุการณที่ไมคอยเขาทาทีต ่ อ  งการความดูแลเปนพิเศษ โดยทั่วไปในการเขียนโปรแกรมที่ดีนั้น เรา จะตองตรวจสอบถึงเหตุการณที่อาจทําใหโปรแกรมของเราลมเหลวในการทํางาน เชน ขอมูลถูกหารดวย ศูนย เขาหาขอมูลใน array ดวยการใช index ที่ไมมีอยูจ  ริง หรือ อางถึงหนวยความจําที่เปน null เปนตน ถึงแมวาเรามีวิธก ี ารตรวจสอบ error ตาง ๆ เหลานี้ดว ยการใช if-else หรือ การตรวจสอบอื่น ๆ ที่ทําให โปรแกรมของเราทํางานไดราบรื่น แตจะทําให code ของเราดูแลววุนวายเพราะถามีการตรวจสอบ error มาก code ของเราก็จะดูซับซอนมากยิ่งขึ้น แตไมไดหมายความวาเราจะไมตรวจสอบ และดักจับ error เหลานี้ การนําเอา exception เขามาเปนตัวชวยในการตรวจสอบและดักจับ ทําใหเกิดการแยกสวนของ code ที่ทํางานไดราบรื่น ออกจากสวนของ code ที่จัดการเกี่ยวกับ error ทําใหเราสามารถที่จะคนหาสวน ของ code ทั้งสองไดงายขึ้น ถามีการเปลีย ่ นแปลง code ในอนาคต ขอดีอก ี อันหนึ่งของ exception ก็คือ ทําใหการตรวจสอบและดักจับเปนไปอยางเฉพาะเจาะจง ตรงกับ error ที่เกิดขึ้น ทําใหการแกไขเปนไป อยางถูกตอง และเนื่องจากวา error มีหลากหลายรูปแบบ เราตองเขียน code ขึ้นมารองรับไมเชนนั้นแลว โปรแกรมของเราก็จะไมผานการ compile เราไมจําเปนทีจ ่ ะตองใช exception ในการตรวจสอบและดักจับ error ในโปรแกรมเสมอไป เพราะการใช exception จะเสียคาใชจายในการประมวลผลมาก ทําใหโปรแกรมทํางานชาลง ดังนั้นเราจะตองตัดสินใจ ใหดีวา ควรจะใช exception ในกรณีไหน อยางไร ตัวอยางของโปรแกรมที่ไมตองใช exception ก็นาจะ เปนการใสขอมูลนําเขาแบบผิด ๆ ของ user ซึ่งถือเปนเรื่องปกติ ถาเรามัวแตเสียเวลาในการดักจับดวย การใช exception แทนการตรวจสอบและดักจับทั่วไปโปรแกรมของเราก็จะเสียเวลาในการประมวลผล สวนอื่น ๆ ไป การใช exception ใน Java นั้นจะโดยทั่วไปจะเปนการโยน (throw) การจัดการ error ที่เกิดขึ้นใหกับ สวนของ code ที่ทาํ หนาที่ในดานการจัดการกับ error นั้น ๆ ที่เกิดขึ้น ซึ่ง code สวนนี้จะคอยดักจับ (catch) ถามีการโยนเกิดขึ้น แตไมจําเปนที่ code สวนนี้จะตองแกไข error ที่เกิดขึ้นอาจเปนเพียงการดัก จับเทานั้น เพื่อใหโปรแกรมทํางานตอไปไดเทานั้น เราคงไมพูดถึงขอมูลตาง ๆ ทีเ่ กี่ยวกับ error และ exception มากนักแตจะเนนการใช exception ในการ ตรวจสอบและดักจับ error แบบพอประมาณ ผูทส ี่ นใจก็สามารถที่จะหาอานไดจากหนังสือ Java ทั่ว ๆ ไป หรือใน web sit ของ Java เอง Exception โดยปกติจะเปน object จาก sub class (class ใด class หนึ่ง) ของ class Throwable ที่ Java มีให และ class หลัก ๆ สอง class ที่เกิดจาก class Throwable โดยตรงที่เปน class หลักของ class ที่เปน class เฉพาะของการจัดการกับ error คือ class Error และ class Exception (ภาพที่ 7.1)


บทที่ 7 เริ่มตนกับ Java

การตรวจสอบและดักจับ error (Exceptions)

189

Throwable

Error

Other sub classes

Exception

Other sub classes

ภาพที่ 7.1 Class Throwable และ sub classes

โดยการออกแบบของ Java เราไมควรทีจ ่ ะ catch error ที่เกิดขึ้นจากการตรวจสอบของ class Error เพราะ error ทีเ่ กิดขึ้นจะเปน error ที่ โดยทัว่ ไปจะไมเกิดขึ้น (หรือไมคาดวาจะเกิด) ซึ่งมีอยูสาม class คือ ThreadDeath LinkageError และ VirtualMachineError เราคงจะไมเขาไปวุนวายกับ class ทั้งสาม เพราะวา เราไมสามารถที่จะแกไข error ที่เกิดขึ้นนี้ไดโดยตรง และตองใชการตรวจสอบอยางละเอียดกับ error ที่เกิดขึ้น (แตคงตองหวังในใจวา error ที่วาคงไมเกิดขึ้นกับเรา) เราจะมาดูตัวอยางการใช exception ในการจัดการกับ error ที่เกิดขึ้นในโปรแกรมของเรา ดวยโปรแกรม ตัวอยางตอไปนี้ //ThrowException.java class ThrowException { public static void main(String[] args) throws Exception { int number = 10; int divider = 0;

}

}

System.out.println("Divide " + number + " by " + divider); int result = number / divider; System.out.println("Result is " + result);

โปรแกรมตัวอยางดานบนนีท ้ ําการ throw exception ซึ่งเปน exception ที่เกิดขึ้นในขณะที่โปรแกรม กําลังไดรับการประมวลผล (เชน การหารตัวเลขที่เปน int ดวย 0 – เราตั้งใจให error นี้เกิดขึ้น) โปรแกรม ตัวอยางของเราไมไดทําการดักจับใด ๆ ทําแตเฉพาะการตรวจสอบ error ที่เกิดขึ้นเทานัน ้ ดังที่เห็นจาก ผลลัพธของการ run นี้ Divide 10 by 0 java.lang.ArithmeticException: / by zero at ThrowException.main(ThrowException.java:10) จะเห็นวา Java จะฟองใหเรารูว า error ที่เกิดขึ้นเปน error ชนิดไหน (ArithmeticException) ที่พยายาม หาร int ดวย 0 พรอมกับบอกวาเกิดขึ้นในบรรทัดที่เทาไร หลังจากนั้นก็ยุตก ิ ารทํางาน ถาหากวาเราตองการที่จะแกไข หรือทําการใด ๆ สักอยางหนึ่งกับ error ทีเ่ กิดขึ้นเราตองใช try และ catch ดังตัวอยางตอไปนี้

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 7 เริ่มตนกับ Java

การตรวจสอบและดักจับ error (Exceptions)

190

//TryAndCatchExample1.java //adopted from Ivor Horton's class TryAndCatchExample1{ public static void main(String[] args) { int number1 = 15; int number2 = 0; try { System.out.println("Try to divide by zero in a try block."); int result = number1 / number2; System.out.println("Leaving a try block."); } catch(ArithmeticException ex) { System.out.println("Exception caught in a catch block."); }

}

}

System.out.println("After a try block.");

โปรแกรม TryAndCatchExample1.java เปนโปรแกรมตัวอยางการใช try และ catch ในการจัดการกับ การหาร int ดวย 0 (เราจะไมใชการ throws exception เหมือนกับตัวอยางแรก) เรากําหนดให number1 มีคาเปน 15 และ number2 มีคาเปน 0 พรอมทั้งกําหนดให result = number1 / number2; ใน block ของ try ซึ่งประโยคดังกลาวจะทําใหเกิดการโยน exception ไปยัง block ของ catch และใน block ของ catch เราจะดักดวย exception ที่ชื่อ ArithmaticException เราไมไดทําอะไรมากมายไปกวา การแสดงขอความวามีการดักจับ error ผลลัพธที่ไดจากการ run คือ Try to divide by zero in a try block. Exception caught in a catch block. After a try block. จากผลลัพธที่ได code ที่ไดรบ ั การประมวลผลคือ ประโยคทีอ ่ ยูใน block ของ try 2 ประโยคแรก โดยเฉพาะประโยคที่สอง ที่ทาํ ใหการประมวลกระโดดไปยัง block ของ catch ทําใหประโยคที่สามไมได รับการประมวลผล และหลังจากที่ประมวลผลประโยคที่อยูใน block ของ catch แลว การประมวลผล ประโยคสุดทายทีต ่ ามหลัง block ของ catch จึงเกิดขึ้น เราสามารถใช ตัวแปร ex ที่เราไดประกาศใน parameter list ของ method catch() แสดงถึงขอความที่ บงบอกเกี่ยวกับ error ที่เกิดขึ้น ดวยการเพิม ่ ประโยคตอไปนี้ใน block ของ catch System.out.println(ex.getMessage()); ex.printStackTrace(); ประโยคแรกเรียกใช method getMessage() ที่เกิดขึ้นทําการแสดงผลไปยังหนาจอ สวนประโยคทีส ่ อง เปนการตรวจสอบถึงที่มาของ error ที่เกิดขึ้น ดังที่แสดงใหเห็นจากการ run โปรแกรมอีกครั้งหลังจาก การเปลี่ยนแปลง code ใน block ของ catch Try to divide by zero in a try block. Exception caught in a catch block. / by zero java.lang.ArithmeticException: / by zero

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 7 เริ่มตนกับ Java

การตรวจสอบและดักจับ error (Exceptions)

191

at TryAndCatchExample1.main(TryAndCatchExample1.java:11) After a try block. เราไมจําเปนทีจ ่ ะตองแสดงผลที่เกิดขึ้นไปยังหนาจอ สวนใหญแลวขอมูลเหลานี้จะเปนประโยชนตอการ ตรวจสอบถึง error ที่เกิดขึ้นเทานั้นเอง สิ่งทีส ่ ําคัญที่เราตองกังวลก็คือ การตรวจสอบและดักจับ error ที่ อาจเกิดขึ้น Java กําหนดให try และ catch เปนของคูกัน เราไมสามารถทีจ ่ ะแยก block สองออกจากกันได ถาเรา กําหนดใหมีประโยคอะไรก็ไดสักประโยคหนึง่ ระหวาง block ของ try และ catch โปรแกรมของเราจะ compile ไมผาน ดังตัวอยางทีม ่ ีการเพิ่มประโยคระหวาง block ทั้งสองนี้ … … System.out.println("Leaving a try block.");

} System.out.pritnln("In between try and catch blocks."); catch(ArithmeticException ex) { … … ถาเรา compile เราจะได error ดังที่เห็นนี้ TryAndCatchExample1.java:9: 'try' without 'catch' or 'finally' try { ^ TryAndCatchExample1.java:15: 'catch' without 'try' catch(ArithmeticException ex) { ^ 2 errors ตัวอยางการใช try และ catch ที่ classic อีกอันหนึ่งก็คือ การใช try และ catch ใน loop ดังตัวอยาง ตอไปนี้ //TryAndCatchExample2.java //adopted from Ivor Horton's class TryAndCatchExample2 { public static void main(String[] args) { int number = 10; for(int index = 5; index >= -1; index--) try { System.out.println("try block: index = " + index); int result = number / index; System.out.println("Leaving a try block."); } catch(ArithmeticException e) { System.out.println("Exception caught in a catch block."); System.out.println(e.getMessage()); e.printStackTrace(); }

}

}

System.out.println("After a try and catch blocks.");

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 7 เริ่มตนกับ Java

การตรวจสอบและดักจับ error (Exceptions)

192

กอนที่จะอธิบายถึงการทํางานของตัวโปรแกรม เรามาดูผลลัพธที่ไดจากการ run try block: index = 5 Leaving a try block. try block: index = 4 Leaving a try block. try block: index = 3 Leaving a try block. try block: index = 2 Leaving a try block. try block: index = 1 Leaving a try block. try block: index = 0 Exception caught in a catch block. / by zero java.lang.ArithmeticException: / by zero at TryAndCatchExample2.main(TryAndCatchExample2.java:11) try block: index = -1 Leaving a try block. After a try and catch blocks. ประโยคใน block ของ try จะถูกประมวลผลจนกวา คาของ index จะเปน 0 จึงจะกระโดดไปประมวลผล ประโยคที่อยูใน block ของ catch หลังจากนัน ้ ก็กลับไปประมวลผลประโยคที่เหลืออยูใน block ของ try และประโยคทีอ ่ ยูทายสุดในโปรแกรม อีกประโยคหนึ่ง จะเห็นไดวาเรามีทางเลือกอยูส  องทางในการจัดการกับ error ทางแรกคือ ยุติการทํางาน (terminate) ของโปรแกรม หรือ code สวนนั้น ๆ ที่ทําใหเกิด error หรือ ทางที่สอง ซึ่งเปนทางเลือกทีท ่ ําใหโปรแกรม หรือ code สวนนั้น ๆ กลับไปรับการประมวลผลใหม (resumption) ทั้งสองวิธีเปนการตรวจสอบและดักจับ error ที่ดีพอกัน ทั้งนี้ก็ขึ้นอยูก  ับลักษณะของงานทีท ่ ําอยู ลองมาดูตัวอยางอีกสักตัวหนึ่งในการใช class NumberFormatException ในการดักจับ error //NumFormatException.java import java.lang.Integer; class NumFormatException { public static void main(String[] args) { int inputNum, sum = 0;

}

//reading input from argument list //only those in [0..9] for(int i = 0; i < args.length; i++) { try { inputNum = Integer.parseInt(args[i]); sum += inputNum; } //ignore input that's not a number catch(NumberFormatException e) { e.printStackTrace(System.out); } } System.out.println("Sum is " + sum);

}

เรากําหนดใหโปรแกรมของเรารับขอมูลจาก command line argument ซึ่งเปนวิธีการทีย ่ อมใหผใู ชใส ขอมูลตามหลังชื่อของโปรแกรม (ดูจากผลลัพธการ run) เราจะทําการหาผลรวมของตัวเลขเหลานั้น

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 7 เริ่มตนกับ Java

การตรวจสอบและดักจับ error (Exceptions)

193

ทั้งหมดจนกวาผูใชจะพอใจ คือ กดปุม <enter> หลังจากใสขอความจนพอใจ ใน catch block เราดักจับ ดวย NumberFormatException ซึ่งจะไมยอมรับขอมูลนําเขาที่ไมใชตัวเลขที่เปน int และทุกครั้งที่เจอ ขอมูลแบบนี้โปรแกรมจะสงรายละเอียดไปใหผูใช และจะหาผลรวมของขอมูลทีถ ่ ูกตองนั้น ดังที่แสดงไว ดานลางนี้ >java NumFormatException 1 2 3 4 p 5 6 java.lang.NumberFormatException: For input string: "p" at java.lang.NumberFormatException.forInputString(NumberFormatException. java:48) at java.lang.Integer.parseInt(Integer.java:426) at java.lang.Integer.parseInt(Integer.java:476) at NumFormatException.main(NumFormatException.java:12) Sum is 21 ในการสราง block สําหรับการ catch error ที่เกิดขึ้นเราไมจําเปนที่จะตองมี catch block เพียง block เดียว เราอาจมีมากกวาหนึ่ง catch block ไดแตมีขอแมวา การ catch exception ตองทําจาก sub class ออกไปหา super class มิฉะนัน ้ แลวการดักจับในหลาย ๆ block อาจไมเกิดขึ้น เชน try { … … } catch(Exception e) { … … } catch(ArithmeticException ex) { … .. } เนื่องจากวา class ArithmeticException เปน class ที่เกิดมาจาก class Exception ดังนัน ้ error ที่ เกิดขึ้นก็จะถูกดักจับใน catch block ทั้งหมด การดักจับใน catch block ทีส ่ องจึงไมเกิดขึ้น เรามาลองดูตัวอยางการดักจับ error ในรูปแบบนี้กันดู //MultipleCatches.java class MultipleCatches { public static void main(String[] args) { //force divide by zero at index = 2 int []number = {1, 2, 0, 4}; int num = 12; //force array index out of bound at index = 4 for(int i = 0; i < number.length + 1; i++) { try { num /= number[i]; System.out.println("result = " + num); } catch(ArithmeticException e) { System.out.println("error message: " + e.getMessage()); e.printStackTrace(); } catch(ArrayIndexOutOfBoundsException e) {

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 7 เริ่มตนกับ Java

การตรวจสอบและดักจับ error (Exceptions)

194

System.out.println("error message: " + e.getMessage()); e.printStackTrace();

}

}

} } System.out.println("After a for loop.");

เราตองการที่จะบังคับใหเกิด error สองอยางคือ หารดวยศูนย และเขาหา index ของ array ที่ไมมีอยู จริง โดยเรากําหนดใหขอมูลที่ index = 2 มีคาเปนศูนย และให for loop ทํางานเกินไปหนึ่งครั้ง การ run โปรแกรมตัวอยางของเราทําใหเกิด ผลลัพธดังนี้คือ result = 12 result = 6 error message: / by zero java.lang.ArithmeticException: / by zero at MultipleCatches.main(MultipleCatches.java:11) result = 1 error message: 4 java.lang.ArrayIndexOutOfBoundsException: 4 at MultipleCatches.main(MultipleCatches.java:11) After a for loop. จะเห็นวาโปรแกรมของเราดักจับ error ไดตามที่เราตั้งใจไว การหารดวยศูนย และการอางถึง index ของ array ที่ไมมีอยูจริง ถูกดักไวทั้งสองตัว ถาเปนการจัดการที่เปนการพัฒนาโปรแกรมจริง ๆ เราคงทําแค การดักจับไมได คงตองมีกระบวนการอื่น ๆ ในการทําใหโปรแกรมทํางานไดอยางราบรื่น และกระบวนการ จัดการกับ error ที่เกิดขึ้นก็ตองมีความซับซอนเพิ่มขึ้น Java ยังมี block อีก block หนึ่งที่เอาไว catch error ที่เกิดขึ้น ที่ซึ่งเปน block สุดทายของการ catch ทั้งหมด โดยกําหนดให block นี้ทีชื่อวา finally Finally เปนการดักจับ error สุดทายของการดักทั้งหมด ดังนั้น finally จะอยูที่อื่นไมไดนอกจาก block สุดทายของ catch block ทั้งหมด เราจะแสดงใหดู ดวยการนําเอา finally ไปใสไวเปน block สุดทายใน ตัวอยางกอนหนานี้ ดังนี้ … …

} catch(ArrayIndexOutOfBoundsException e) { System.out.println("error message: " + e.getMessage()); e.printStackTrace(); } finally { System.out.println("In finally block."); } … … finally block ที่เราใชจะถูกประมวลผลเสมอ ไมวาอะไรจะเกิดขึ้นก็ตามใน block อื่น ๆ กอนหนา ดัง ตัวอยางของผลลัพธทแ ี่ สดงใหดูบางสวนนี้ …

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 7 เริ่มตนกับ Java

การตรวจสอบและดักจับ error (Exceptions)

195

… at MultipleCatches.main(MultipleCatches.java:13) In finally block. After a for loop. โดยทั่วไปหนาที่หลักของ finally จะเปนการเก็บกวาด code ที่โปรแกรมตองการประมวลผล (เชน การปด เปดไฟล)กอนออกจาก ตัว method main() และกลับออกไปสูระบบในที่สด ุ //ThrowsWithTry.java import java.io.*; import java.lang.Integer; class ThrowsWithTry { public static void main(String[] args) throws IOException { BufferedReader buffer; InputStreamReader isr; String input; int first, divider; //keep looping until error occur while(true) { System.out.print("Enter a number: "); isr = new InputStreamReader(System.in); buffer = new BufferedReader(isr); //get first number input = buffer.readLine(); first = Integer.parseInt(input); //get second number System.out.print("Enter a divider: "); input = buffer.readLine(); divider = Integer.parseInt(input);

}

}

}

try { double result = first / divider; System.out.println("Result = " + result); } catch(ArithmeticException e) { System.out.println("Exception: " + e.getMessage()); e.printStackTrace(); }

โปรแกรม ThrowsWithTry.java เปนโปรแกรมที่ตองการแสดงการใช throws และ try – catch ควบคูกน ั โดยตัวโปรแกรมเองจะทําการอานขอมูลสองตัวจาก keyboard ซึ่งกําหนดใหขอมูลทั้งสองตัวเปน int และจะทําการหาผลลัพธของการหารขอมูลตัวแรก ดวยขอมูลตัวทีส ่ อง โปรแกรมจะหยุดการทํางานก็ตอ  เมื่อผูใชใสขอมูลที่ไมใชตวั เลข และจะทําการฟองถาขอมูลตัวที่สองของ การหารมีคาเปนศูนย ผลลัพธที่ไดจากการ run คือ Enter a number: 23 Enter a divider: 5 Result = 4.0 Enter a number: 56

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 7 เริ่มตนกับ Java

การตรวจสอบและดักจับ error (Exceptions)

196

Enter a divider: 0 Exception: / by zero java.lang.ArithmeticException: / by zero at ThrowsWithTry.main(ThrowsWithTry.java:27) Enter a number: 12 Enter a divider: 3 Result = 4.0 Enter a number: pop Exception in thread "main" java.lang.NumberFormatException: For input string: "pop" at java.lang.NumberFormatException.forInputString(NumberFormatException. java:48) at java.lang.Integer.parseInt(Integer.java:426) at java.lang.Integer.parseInt(Integer.java:476) at ThrowsWithTry.main(ThrowsWithTry.java:20) จากผลลัพธที่ไดจะเห็นวาโปรแกรมของเราจะฟองถามีการหารดวยศูนย และหยุดถาขอมูลไมใช int (ใน ตัวอยางนีผ ้ ูใชใสคําวา "pop") โปรแกรมของเราจะทํางานไปเรื่อย ๆ ถาผูใ ชใสขอมูลที่ถูกตองตามที่ โปรแกรมไดกําหนดไว แตนี่ไมใชการตรวจสอบที่ดีเทาไรนัก ถาเราตองการที่จะบอกผูใชวา ขอมูลไม ถูกตอง และใหใสขอมูลใหมเราก็ตองแกไข code ของเราใหรองรับการทําใหม ซึ่งอาจทําไดดังนี้ //ThrowsWithTry1.java import java.io.*; import java.lang.Integer; class ThrowsWithTry1 { public static void main(String[] args) throws IOException { BufferedReader buffer; InputStreamReader isr; String input; int first = 0, divider = 0; while(true) { System.out.print("Enter a number: "); isr = new InputStreamReader(System.in); buffer = new BufferedReader(isr); //get first number input = buffer.readLine(); first = readInt(input); //get second number only if first number is valid if(first != -1) { System.out.print("Enter a divider: "); input = buffer.readLine(); divider = readInt(input); } //perform division if both numbers are valid if(first != -1 && divider != -1) { try { double result = first / divider; System.out.println("Result = " + result); } catch(ArithmeticException e) { System.out.println("Exception: " + e.getMessage());

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 7 เริ่มตนกับ Java

}

}

}

การตรวจสอบและดักจับ error (Exceptions)

}

}

197

e.printStackTrace();

//method to convert an int from a string public static int readInt(String in) throws IOException { try { int num = Integer.parseInt(in); return num; } catch(NumberFormatException e) { System.out.println("Exception caught: " + e.getMessage()); return -1; } }

เราไดเขียน method readInt() สําหรับการเปลี่ยน string ที่อานจาก buffer ใหเปน int โดยเราไดใช try และ catch ในการตรวจสอบและดักจับ error ที่อาจเกิดขึ้นจากการใสขอมูลผิดพลาดที่อาจเกิดขึ้นของ ผูใช และเรากําหนดใหสงคา -1 กลับออกไปเพื่อใชเปนตัวบอกให code ใน while loop รูวา ขอมูลไม ถูกตอง เพื่อที่เราจะไดไมตองอานขอมูลตัวทีส ่ อง ในสวนของ code ใน while loop เราไดทําการ เปลี่ยนแปลงการอาน และ การประมวลผลใหเปน //get second number only if first number is valid if(first != -1) { System.out.print("Enter a divider: "); input = buffer.readLine(); divider = readInt(input); } //perform division if both numbers are valid if(first != -1 && divider != -1) { try { double result = first / divider; System.out.println("Result = " + result); } catch(ArithmeticException e) { System.out.println("Exception: " + e.getMessage()); e.printStackTrace(); } } โปรแกรมของเราจะทําการประมวลผลถาขอมูลทั้งสองเปนขอมูลที่ถูกตอง ดังนั้นเราจึงตองทําการ ตรวจสอบวา first และ divider มีคาทีถ ่ ูกตองหรือไมดวยการตรวจสอบกับ -1 ซึ่งถาตรวจสอบแลวได ขอมูลที่ถูกตอง เราก็จะทําการประมวลผลขอมูลทั้งสอง ลองมาดูผลลัพธกัน Enter a number: 23 Enter a divider: 3 Result = 7.0 Enter a number: p Exception caught: For input string: "p" Enter a number: 3 Enter a divider: p Exception caught: For input string: "p" Enter a number: 32 Enter a divider: 0

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 7 เริ่มตนกับ Java

การตรวจสอบและดักจับ error (Exceptions)

198

Exception: / by zero java.lang.ArithmeticException: / by zero at ThrowsWithTry1.main(ThrowsWithTry.java:34) Enter a number: -1 Enter a number: Exception caught: null Enter a number: จะเห็นไดวาโปรแกรมของเราทํางานไดอยางที่ไดตั้งใจไว คือ ตรวจสอบขอมูลทั้งสอง พรอมทั้งทําการ ประมวลผลถาขอมูลทั้งสองถูกตอง ผูอานควรสังเกตดวยวา โปรแกรมตัวอยางนี้ยังไมสมบรูณเลยทีเดียว ดังจะเห็นไดจากการใสขอมูลที่เปน -1 ทําไม? พรอมกันนี้เรายังไมสามารถออกจากโปรแกรมได ถาไมใช คําสั่ง <crtl> + c ในการเขียนโปรแกรมที่ตองรองรับการทํางานที่มีการตรวจสอบเพื่อใหเกิดความถูกตองนั้น เราตอง คํานึงถึงปจจัยหลายดาน ทั้งนี้ก็ขึ้นอยูกับลักษณะของงานทีเ่ ราตองเขียนโปรแกรมรองรับ โปรแกรม ตัวอยางของเราตองการแสดงใหเห็นถึงการตรวจสอบและดักจับ error และแกไขในระดับหนึ่งเทานั้น ดังนั้นผูเขียนจึงไมไดแสดงถึงการแกไขทั้งหมด เพราะขอกําหนดของงานยังไมชัดเจน การสราง exception ขึ้นมาใชเอง Java ยอมใหเราสราง exception ขึ้นมาใชกับโปรแกรมตาง ๆ ที่เราคิดวานาจะเพิ่มขอมูลบางอยางใหกับ ผูใช ถาหากมี error เกิดขึ้น เชน การหารดวยศูนยที่เราไดเขียนขึ้นมากอนหนานี้ เราอาจตองการบอก รายละเอียดใหมากกวาเดิมแกผูใช เราจะใชโปรแกรมการหารดวยศูนยที่มีการเปลี่ยนแปลงบางอยาง เปน ตัวอยางตอไป //TestInputValidation.java import java.io.*; import java.lang.Integer; class TestInputValidation { public static void main(String[] args) throws Exception { BufferedReader buffer; InputStreamReader isr; String input; int first, divider; while(true) { //get first number first = readInt(); //get second number only if first number is valid divider = readInt();

}

}

//perform division if both numbers are valid try { //calling method divide() int result = divide(first,divider); System.out.println("Result = " + result); } //catching user defined exception catch(ZeroDivideException e) { e.printStackTrace(System.err); }

//method to get an int from the keyboard

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 7 เริ่มตนกับ Java

การตรวจสอบและดักจับ error (Exceptions)

199

public static int readInt() throws Exception { BufferedReader buffer; InputStreamReader isr; String input = null; int result = 0; boolean ok = false;

}

isr = new InputStreamReader(System.in); buffer = new BufferedReader(isr); //keep looping until user enter an int while(!ok) { System.out.print("Enter a number: "); try { input = buffer.readLine(); result = Integer.parseInt(input); ok = true; } catch(NumberFormatException e) { System.out.println(e.getMessage()); e.printStackTrace(System.err); } } return result;

//method to divide first number by the second number public static int divide(int first, int second) throws ZeroDivideException { int result; try { result = first / second; } catch(ArithmeticException e) { throw new ZeroDivideException(); //throw new exception } return result; } } เราไดเปลี่ยนโปรแกรมกอนหนานี้มากพอสมควรในการที่จะอานขอมูลใหถก ู ตอง พรอมทัง้ แสดงถึงการ เขียน exception ขึ้นมาใชเอง เราเริ่มดวยการสราง method readInt() ขึ้นมาใหม โดยกําหนดใหผูใช ตองใสขอมูลใหถูกตอง ถาไมถูกเราก็จะวนกลับไปถามใหมจนกวาจะได Method ตัวทีส ่ องที่เราสรางขึน ้ มาคือ method divide() ที่รบ ั parameter 2 ตัว ทําหนาทีใ่ นการหาร ตัวเลขตัวแรกดวยตัวเลขตัวทีส ่ อง ภายใน method divide() นี้เราจะดักจับ error ที่เกิดขึน ้ ผานทาง ArithmeticException ดวย การ throw exception ที่เราไดสรางขึ้นเอง ดวยคําสั่ง catch(ArithmeticException e) { throw new ZeroDivideException(); //throw new exception } แตกอนที่เราจะเรียกใช exception ที่วานี้เราตองสราง code สําหรับ exception เสียกอน ซึง่ เราได ออกแบบใหเปนการดักจับแบบงาย ๆ ดวยการสราง class ZeroDivideException จาก class Exception เพื่อที่จะใหเราสามารถที่จะไดรับการถายทอดคุณสมบัติจาก class Exception เรากําหนดให code ของ class ZeroDivideException มีดังนี้ //ZeroDivideException.java

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 7 เริ่มตนกับ Java

การตรวจสอบและดักจับ error (Exceptions)

200

class ZeroDivideException extends Exception { //default constructor ZeroDivideException() { super("divide by zero"); //call super class' constructor }

}

ZeroDivideException(String message) { super(message); }

เราไมไดทําอะไรมากไปกวาเรียกใช constructor ของ class Exception ดวยขอความที่เราตองการให ปรากฏหาก error ที่วานี้เกิดขึน ้ (divide by zero) ภายในตัว method main() เอง code สวนทีส ่ ําคัญคือ try { //calling method divide() int result = divide(first,divider); System.out.println("Result = " + result); } //catching user defined exception catch(ZeroDivideException e) { e.printStackTrace(System.err); } เราเรียก method divide() ภายใน try และถาหากการหารที่เกิดขึ้นมี error มันก็จะถูกจับใน catch block ที่เราไดเรียกดวย object ที่มาจาก class ZeroDivideException ที่เราไดสรางขึ้น หลังจากที่ลอง run ดู เราไดผลลัพธดงั นี้ Enter a number: 45 Enter a number: 36 Result = 1 Enter a number: 0 Enter a number: 3 Result = 0 Enter a number: pop For input string: "pop" java.lang.NumberFormatException: For input string: "pop" at java.lang.NumberFormatException.forInputString(NumberFormatException. java:48) at java.lang.Integer.parseInt(Integer.java:426) at java.lang.Integer.parseInt(Integer.java:476) at TestInputValidation.readInt(TestInputValidation.java:47) at TestInputValidation.main(TestInputValidation.java:16) Enter a number: 3 Enter a number: 0 ZeroDivideException: divide by zero at TestInputValidation.divide(TestInputValidation.java:64) at TestInputValidation.main(TestInputValidation.java:23) Enter a number: null (เราออกจากโปรแกรมดวยการกด <crtl> + c ณ ตําแหนงนี้) java.lang.NumberFormatException: null at java.lang.Integer.parseInt(Integer.java:394) at java.lang.Integer.parseInt(Integer.java:476)

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 7 เริ่มตนกับ Java

การตรวจสอบและดักจับ error (Exceptions)

201

at TestInputValidation.readInt(TestInputValidation.java:47) at TestInputValidation.main(TestInputValidation.java:16) Enter a number: ผลลัพธที่ไดก็เปนไปตามที่เราไดคาดไว คือ error ถูกดักจับไวไดหมด ผูอานควรสังเกตดวยวาเรายังใช loop ใน method main() ดังนั้นการออกจาก loop ก็ตองใช <crtl> + c เหมือนเดิม ทําใหมีการดักจับ error ที่เกิดขึ้นครั้งสุดทายกอนออกจากโปรแกรม อีกสวนหนึ่งที่นา สนใจในโปรแกรมของเราก็คอ ื การสงขอความบอกถึงรายละเอียดของ error ผานทาง System.err ซึ่งเปนอีกชองทางหนึ่งที่ Java มีใหใชสาํ หรับการสงขอมูลทีไ ่ มใชขอมูลปกติออกทาง หนาจอ ถึงแมวา ขอมูลจะออกไปที่เดียวกันแตชองทางการสงออก ไมเหมือนกัน สาเหตุที่เปนเชนนี้ก็ เพื่อใหมีการแยกแยะ error ออกจากขอมูลหรือผลลัพธปกติของโปรแกรม เรามาดูอีกสักตัวอยางหนึ่ง //CheckRange.java import java.lang.Integer; class CheckRange { public static void main(String[] args) { try { //getting input from argument list int first = Integer.parseInt(args[0]); int second = Integer.parseInt(args[1]); int third = Integer.parseInt(args[2]); //check if the third input is between first and second checked(first, second, third); System.out.println("Number " + third + " is in the given range");

}

}

} catch(OutOfRangeException e) { e.printStackTrace(System.err); }

//method to validate range public static void checked(int start, int stop, int num) throws OutOfRangeException { if(num < start) { String errMsg = new String(num + " < " + start); throw new OutOfRangeException(errMsg, start, stop); } if(num > stop) { String errMsg = new String(num + " > " + stop); throw new OutOfRangeException(errMsg, start, stop); } }

โปรแกรมตัวอยางนี้รับขอมูลผานทาง argument list ที่เปนตัวเลขสามตัว โดยจะทําการตรวจสอบวา ตัวเลขตัวทีส ่ ามอยูระหวางตัวแรกและตัวทีส ่ องหรือไม ถาไมก็จะ throw exception OutOfRangeException ที่ไดเขียนขึ้น ดังนี้ //OutOfRangeException.java

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 7 เริ่มตนกับ Java

การตรวจสอบและดักจับ error (Exceptions)

202

public class OutOfRangeException extends Exception { //default constructor OutOfRangeException() {} //constructor OutOfRangeException(String message, int p, int q) { super(message); }

}

จะเห็นวาโดยสวนใหญแลวเราจะเรียกใช super class constructor ใหทํางานใหเรา มากกวาที่จะเขียน code ขึ้นมา ซึ่งเปนสิ่งทีท ่ ําใหการออกแบบของเราไวขึ้น เราเพียงแตเขียนถึงสิ่งที่บงบอกถึง error ที เกิดขึ้นวาเปนอะไรเทานั้นเอง จากการ run ผลลัพธที่เราไดคือ >java CheckRange 12 45 569 OutOfRangeException: 569 > 45 at CheckRange.checked(CheckRange.java:31) at CheckRange.main(CheckRange.java:15); E:\bc221Book\source>java CheckRange 12 45 2 OutOfRangeException: 2 < 12 at CheckRange.checked(CheckRange.java:27) at CheckRange.main(CheckRange.java:15) E:\bc221Book\source>java CheckRange 12 45 15 Number 15 is in the given range สรุป ในการเขียนโปรแกรมที่ดีนั้น ผูเขียนจะตองคํานึงถึง error ที่อาจเกิดขึ้นในโปรแกรม ซึ่งไดแบงออกเปน สองลักษณะใหญ คือ error ทีโ่ ปรแกรมเมอรไมมีทางแกไขได คือ อยูนอกเหนือการควบคุมของ ผูพัฒนาโปรแกรม เชน error ที่เกิดจากหนวยความจําไมพอเพียง สวน error อีกอันหนึ่งที่ผูเขียน โปรแกรมตองตรวจสอบก็คือ error ที่เกิดตอน run โปรแกรม เชน error จากการหารดวยศูนย การเขาหา Index ของ array ที่ไมมีอยูจริง การปอนขอมูลที่ไมถูกกับชนิดทีต ่ องการ อยางนี้เปนตน Exception ที่ Java มีใหมีอยูมากพอสมควร และมากพอทีจ ่ ะเรียกใชไดเกือบทุกกรณีของการเขียน โปรแกรม แตถา ผูเขียนโปรแกรมไดพฒ ั นาโปรแกรมที่ไมสามารถใช exception ที่ Java มีใหก็สามารถที่ จะออกแบบ exception ขึ้นมาใชเองได ในการดัก error นั้นผูเขียนอาจสราง exception ขึ้นมาใชในการดักจับ error เองได ทั้งนี้ก็ขึ้นอยูกับ ลักษณะของงานที่ผูเขียนโปรแกรมกําลังพัฒนาอยู โดยสรุปแลวสิ่งทีต ่ องควรคํานึงในการตรวจจับ error คือ 9 9 9 9 9 9

Exception เปนตัวบงชีถ ้ ึง error ที่เกิดในโปรแกรม Exception เปน object ที่เกิดมาจาก class Throwable เราสามารถทีจ ่ ะเรียกใช exception ที่มาจาก Java โดยตรง หรือ สรางขึ้นมาใชเอง ถาเราตองการที่จะควบคุม exception ใน method เราตองเขียน code ใน try block และไมจําเปนที่ จะตองมี try block เพียงหนึ่ง block เทานั้น อาจมีมากกวาหนึ่ง block ได Code ทีใ่ ชในการควบคุม หรือ แกไข exception จะตองทําใน catch block ที่ตามหลัง try block ทันทีและในหนึง่ try block เราสามารถที่จะมี catch block มากกวาหนึ่งตัวได Finally เปน block ทายสุดที่อยูใน try โดยทัว่ ไปจะใช finally block ในการเก็บกวาดการทํางานของ โปรแกรม เชน การปดไฟล

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 7 เริ่มตนกับ Java

การตรวจสอบและดักจับ error (Exceptions)

203

แบบฝกหัด 1. จงเขียนโปรแกรมทีร่ ับขอมูลจาก keyboard เฉพาะที่เปน int เทานั้นใหใช exception ในการดักจับ error ที่ผูใชอาจใสผด ิ เชน ใสตัวอักษร ใหแสดงขอความฟองทันทีทผ ี่ ูใชใสผิด 2. จงปรับปรุงโปรแกรมที่เขียนขึ้นในขอหนึ่ง โดยเพิ่มการตรวจสอบที่ไมรับตัวเลขที่ต่ํากวาศูนย 3. จงเขียนโปรแกรมทีร่ ับขอมูลจาก keyboard เปนตัวเลขสามตัว โดยกําหนดให ตัวแรกเปนจุดเริ่มตน ตัวทีส ่ องเปน จุดจบ ของคาขององศา Celsius และตัวทีส ่ ามเปนตัวกําหนดการเพิ่มคา (step) ให โปรแกรมทําการคํานวณหา องศา Fahrenheit ตามขอมูลที่กําหนดไวในสองตัวแรก และใหทําการ เพิ่มขึ้นตามคาของขอมูลตัวทีส ่ าม ดังตัวอยางผลลัพธที่แสดงใหดูนี้ >java Temperature 0 100 10 CELSIUS 0 10 20 30 40 50 60 70 80 90 100

FAHRENHEIT 32.0 50.0 68.0 86.0 104.0 122.0 140.0 158.0 176.0 194.0 212.0

ใหทาํ การตรวจสอบ และดักจับ error ที่อาจเกิดขึ้นจากการใสขอมูลที่ไมถูกตอง เชน คาของการเพิ่ม เปนตัวเลขที่นอ  ยกวาศูนย (negative number) คาเริ่มตน มากกวาคาสุดทาย และจํานวนขอมูลที่ นําเขามีจํานวนไมครบตามที่กาํ หนด ตัวอยางของ error ที่เกิดขึ้น >java Temperature 0 100 -5 3rd arg < 0 NUMBER = -5 >java Temperature 40 20 5 Ordering Err FIRST = 40 SECOND = 20 >java Temperature 10 40 java.lang.ArrayIndexOutOfBoundsException: at Temperature.main(Temperature.java:41) 4. จงเขียนโปรแกรมทีห ่ าคาของ mn โดยกําหนดใหทั้ง m และ n มาจาก command line argument list ใหทําการตรวจสอบและดักจับ error ทุก ๆ กรณีที่อาจทําใหโปรแกรมไมทํางาน 5. จงปรับปรุง class Account ในบททีห ่ กใหมีการตรวจสอบและดักจับ error ทีอ ่ าจเกิดขึ้นในการ ถอน เงิน ฝากเงิน และ คิดดอกเบี้ย ถา method ใด ๆ ทีท ่ ําหนาทีด ่ ังกลาวไมมี ใหเขียนขึ้นใหม พรอมทั้ง เขียนโปรแกรมทดสอบ 6. จงปรับปรุงโปรแกรมในขอ เจ็ด แปด และ เกา ในบทที่หา ใหมีการตรวจสอบและดักจับ error พรอม ทั้งเขียนโปรแกรมทดสอบ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


ในบทที่แปดนี้เราจะพูดถึงการอาน และเขียนขอมูลผานทาง stream หรือชองทางการสงขอมูล เราจะดูถึง วิธีการ กระบวนการตาง ๆ ที่เกีย ่ วของกับขอมูลนําเขา และการนําขอมูลออก หลังจากจบบทนี้แลว ผูอานจะไดทราบถึง o o o o o

ความหมายของ stream Class ตาง ๆ ที่ Java มีใหในการประมวลผลดวย stream การสราง directory การสราง file การเปดและปด file การอานและเขียน file ขอแตกตางระหวาง text file และ binary file

ในการทํางานทีเ่ กี่ยวของกับไฟลใน Java นั้นจะตองทําผานทาง stream ซึ่งเปนตัวแทนของอุปกรณที่ นําเขา (input) หรือสงออก (output) ขอมูล เราสามารถเขียน และอานขอมูลผานทาง stream ดวย วิธีการตาง ๆ ในรูปแบบตาง ๆ กัน เชน อานขอมูลจาก keyboard ทีละหนึ่งตัวอักษร หรือทีละ 10 byte โดยทั่วไป ขอมูลนําเขาจะมาจาก keyboard หนวยความจําสํารอง (disk) หรือ อุปกรณอื่น ๆ เชน scanner light-pen memory-card แตโดยสวนใหญแลวมักจะมาจาก keyboard และ disk ในบทนี้เราจะ ใชอุปกรณทั้งสองที่ไดกลาวมา เปนชองทางหลักในการนําเขาขอมูล และจะใชชองทางสงออกเพียงสอง ทางคือ จอ (monitor) และ เครื่องพิมพ (printer) รูปแบบพื้นฐานของขอมูลที่ Java รูจักมีอยูส  องลักษณะคือ binary streams และ character streams ซึ่ง มีความแตกตางกันในรูปแบบของการจัดเก็บ ถาเราเขียนขอมูลเขาสู stream โดยเขียนทีละ byte หรือ ที ละหลาย ๆ byte เราเรียกขอมูลเหลานี้วา binary data การเขียนจะไมมีกระบวนการอื่นใดมายุงเกี่ยว (เชน การเปลี่ยนขอมูลใหอยูใ นรูปแบบอื่นกอนการจัดเก็บ) ขอมูลจะถูกสงเขาสู stream ตามที่ปรากฏอยูใ น memory เชน ถา memory สวนนี้เก็บขอมูลที่เปนตัวเลขอยู ตัวเลขเหลานีจ ้ ะถูกสงเขาสู streams ตามที่ ปรากฏใน memory ในการเก็บขอมูลที่เปน character streams นั้นโดยทั่วไปจะทํากับขอมูลที่เปนตัวอักษร (text) เราจะใช character streams ในการอานไฟลที่เปน text ตัวเลขที่อยูในไฟลจะถูกเปลี่ยนใหอยูในรูปแบบที่ Java ไดกําหนดขึ้น การอานตัวเลขดวยการใช character streams เปนกระบวนการทีย ่ ุงยากมาก เพราะเราตอง รูวาตัวอักษรที่เปนตัวแทนของตัวเลขนั้นใชกต ี่ ัวอักษรในการเก็บ เชน ถาเราสงตัวเลข 17 ผานทาง character stream ตัวเลขนี้จะถูกเปลี่ยนใหเปนคา ASCII ของ '1' และ '7' หรือ 0x310x37 (เลขฐาน 16) และสมมติวาเราเขียนเลข 727 อีกตัวใน stream ของเราก็จะมีขอมูลเปน 0x310x370x370x320x37 การ อานตัวเลขทั้งสองตัวออกมาจะทําไดยากมากเพราะเราไมรวู าจะตองอานตัวอักษรทีละกี่ตวั ถึงจะไดขอมูล ที่ถูกตองเหมือกับที่ไดเขียนไว เราไดทราบแลววา Java เก็บขอมูลในรูปแบบของ Unicode ดังนั้นในการเขียนขอมูลเขาสู stream ใน รูปแบบของ character ขอมูลจะถูกเปลี่ยน (โดยอัตโนมัติ) ใหอยูในรูปแบบของการเก็บ (local code) ตามที่เครื่องนั้นใชอยู เชนถาเครื่องของเราใชภาษาไทยเปนภาษาหลัก รูปแบบของการเก็บก็จะเปน code ของภาษาไทย (Java เรียกระบบนี้วา localization) ในการอานขอมูลนั้น Java จะเปลีย ่ นขอมูลที่ถูก จัดเก็บในรูปแบบของ local code ใหเปน Unicode กอน โดยสรุปแลวในการเขียนและอานนั้น Java จะ เปลี่ยนขอมูลใหเปน Unicode สวนการจัดเก็บนั้นจะจัดเก็บในรูปแบบของภาษาที่ใชอยูใ นเครื่อง


บทที่ 8 เริ่มตนกับ Java

Streams I/O

205

เราจะมาดูตัวอยางที่เกี่ยวของกับไฟล ในหลาย ๆ รูปแบบเพือ ่ ทําใหเกิดความเขาใจถึงวิธีการ และ กระบวนการตาง ๆ ที่เกี่ยวของกับ input และ output เราจะเริ่มตนดวยการตรวจสอบขอมูลตาง ๆ ที่ เกี่ยวกับไฟล จากโปรแกรม FileInfo.java //FileInfo.java import java.io.*; class FileInfo { public static void main(String[] args) { //get path from command-line argument File path = new File(args[0]);

}

}

//display some info. about this file if(path.exists()) { System.out.println(path + " does exist."); System.out.println("Readable : " + statusOk(path.canRead())); System.out.println("Writable : " + statusOk(path.canWrite())); System.out.println("Directory? : " + statusOk(path.isDirectory())); System.out.println("File? : " + statusOk(path.isFile())); System.out.println("Hidden? : " + statusOk(path.isHidden())); } else { System.out.println(path + " does not exist."); }

//return "Yes" or "No" public static String statusOk(boolean yes) { return yes ? "Yes" : "No"; }

โปรแกรมเริม ่ ตนดวยการสราง object path จาก class File ดวยขอมูลที่มาจาก command-line argument ซึ่งอยูในรูปแบบ e:\bc221Book\source e:\bc221Book\source \source \bc221Book\source\FileInfo.java ตัวอยางสองตัวแรกอยูในรูปแบบที่เรียกวา absolute path สวนสองตัวสุดทายอยูในรูปแบที่เรียกวา relative path absolute path เปนการกําหนดที่มาที่ไปดวยตัวอักษรของ drive สวน relative path จะไมมีการกําหนด ตัวอักษรของ drive แตการทํางานทั้งหมดจะอยูภายใน directory นั้น ๆ ดังตัวอยางผลลัพธของการ run นี้ >java FileInfo \bc221Book \bc221Book does exist. Readable : Yes Writable : Yes

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Directory? File? Hidden?

Streams I/O

206

: Yes : No : No

>java FileInfo \bc221Book\source\FileInfo.java \bc221Book\source\FileInfo.java does exist. Readable : Yes Writable : Yes Directory? : No File? : Yes Hidden? : No >java FileInfo \bc221Book\FileInfo.java \bc221Book\FileInfo.java does not exist. ผลลัพธของการ run ทั้งสามครั้งใช relative path เปนตัวกําหนดการคนหา directory และ file สวน ผลลัพธดานลางนี้เปนการาคนหาจาก absolute path E:\bc221Book\source>java FileInfo e:\bc221Book\source\FileInfo.java e:\bc221Book\source\FileInfo.java does exist. Readable : Yes Writable : Yes Directory? : No File? : Yes Hidden? : No เราเรียกใช method ที่มีอยูใน class File ในการตรวจสอบขอมูลของ file วาเปน file ลักษณะไหน ขอมูล เฉพาะคือ อะไร คําวา file ใน Java นั้นเปนไดสองอยาง คือ file ที่เก็บขอมูลที่เราใช (หรือ ระบบใช) และ file ที่เก็บ file หรือทีร่ ียกวา directory (หรือ folder) Java ยังมี method ที่ใชในการตรวจสอบขอมูลของ file อีกหลายตัว เราจะลองใช method เหลานี้ใน โปรแกรมตัวอยางตอไปนี้ //FileInfo1.java import java.io.*; import java.util.Date; class FileInfo1 { public static void main(String[] args) { //explain how to use if no argument is given if(args.length < 1) { System.out.println("Usage: FileInfo1 file-name"); System.exit(1); } //display information about this file echoFileInfo(new File(args[0])); } private static void echoFileInfo(File file) { //display if file is a file or a directory if(file.isFile()) System.out.println("\n" + file + " is a file."); if(file.isDirectory()) { String []list = file.list(); System.out.println("\n" + file + " is a directory."); System.out.println("There are " + list.length + " items in this directory.");

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

}

}

Streams I/O

207

} //lastModifeid() returns amount of milliseconds the file //was last modified, e.g. 1045375241775 since //January 1, 1970, 00:00:00 GMT. We have to create a date //object from this data. long lastModified = file.lastModified(); Date dateModified = new Date(lastModified); //display information about this file System.out.println( "Absolute path: " + file.getAbsolutePath() + "\n Name: " + file.getName() + "\n Parent: " + file.getParent() + "\n Path: " + file.getPath() + "\n Length: " + file.length() + "\n Last modified: " + dateModified);

โปรแกรม FileInfo1.java เรียกใช method 5 ตัวในการแสดงขอมูลของไฟลที่กําหนดให (ผานทาง command-line argument) ซึ่งเปนการเรียกใชโดยตรง และไมมีความยุงยากในการเรียกใช มี method เพียงตัวเดียวเทานั้นที่เราตองปรับปรุงผลลัพธที่ method ตัวนี้สงมาให method ที่วานี้คือ lastModified() lastModified() จะสงคาที่มีชนิดเปน long ที่เปนคาของ วันและเวลาที่ไฟลไดรับการเปลีย ่ นแปลงครั้ง สุดทายในรูปแบบของ millisecond เชน 1045375241775 ซึ่งเราไมสามารถบอกไดวาเปนวันที่เทาไร เวลาอะไร เราตองใชคานีใ้ นการสราง วันขึ้นใหมผานทาง class Date ดังนี้ long lastModified = file.lastModified(); Date dateModified = new Date(lastModified); หลังจากนั้นเราก็แสดงผลออกทางหนาจอ ดังที่แสดงใหดูเปนตัวอยางดานลางนี้ >java FileInfo1 e:\bc221Book\source e:\bc221Book\source is a directory. There are 328 items in this directory. Absolute path: e:\bc221Book\source Name: source Parent: e:\bc221Book Path: e:\bc221Book\source Length: 0 Last modified: Wed Feb 26 07:47:48 GMT+07:00 2003 >java FileInfo1 FileInfo1.java FileInfo1.java is a file. Absolute path: E:\b221Book\source\FileInfo1.java Name: FileInfo1.java Parent: null Path: FileInfo1.java Length: 1236 Last modified: Tue Feb 25 14:06:13 GMT+07:00 2003 >java FileInfo1 Usage: FileInfo1 file-name ตัวอยางตอไปเปนโปรแกรมทีแ ่ สดงรายละเอียดของ directory วาประกอบไปดวยไฟล หรือ subdirectory อะไรบาง

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

208

//DirListing.java //adopted from Bruce Eckel's import java.io.*; import java.util.Arrays; //extract file name from path //must implements FilenameFilter and override method accept() //to get files with given information into a list class DirFilter implements FilenameFilter { String fileName; //constructor DirFilter(String fileName) { this.fileName = fileName; }

}

//this method is called by method list() from class File //to include a file if it contains a given info public boolean accept(File path, String name) { //get only file name String file = new File(name).getName(); //if in fact the file exists we will get the first index //of this file, which causes accept() to return true, //otherwise we will get -1 and returns false return file.indexOf(fileName) != -1; }

class DirListing { public static void main(String[] args) { //create file object with a default directory File path = new File("."); String[] fileList; //list of files with given criteria //no argument provided, get all files on this directory if(args.length == 0) fileList = path.list(); //information provided, get rid of path and extract files //with given info. else fileList = path.list(new DirFilter(args[0]));

}

Arrays.sort(fileList); showDir(fileList);

//sort the list //display the list

//display files to screen public static void showDir(String[] list) { for(int i = 0; i < list.length; i++) System.out.println(list[i]); } }

กอนที่จะอธิบายถึงการทํางานของโปรแกรม เรามาดูผลลัพธ (ตัดทอนบางสวนออก) กันกอน >java DirListing java

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

209

Access.java Account.java Add1To100.java … … AddNumbers2.java ThrowsWithTry.java ThrowsWithTry1.java Triangle.java TryAndCatchExample1.java TryAndCatchExample2.java Two.java UpperLower.java UpperLower2.java Variables.java Vowels.java ZeroDivideException.java p.java >java DirListing te BankRate.class BankRate.java ByteShort.class ByteShort.java Calculate.class Calculate.java โปรแกรม DirListing.java จะแสดงรายการของขอมูลที่อยูใน directory นั้น ๆ ตามขอกําหนดที่เราตั้งให เชนถาเราตองการแสดงไฟลทั้งหมดที่มีอยูเราก็ใชคําสั่ง DirListing โดยไมมีการกําหนดใด ๆ แตถา ตองการแสดงผลดวยขอกําหนด เชน ตองการแสดงไฟลทก ุ ตัวที่มค ี ําวา "te" อยูในไฟลเราก็ใชคาํ สั่ง DirListing te เปนตน โปรแกรมของเราตองเรียกใช interface FileNameFilter เพื่อทําการ override method accept() ที่ทํา หนาทีใ่ นการกรองขอมูลสําหรับให method list() ที่อยูใน class File ใช โดยกําหนดให method accept() ตรวจสอบไฟลจาก path เฉพาะไฟลทถ ี่ ูกตองตามเงื่อนไขที่กําหนดไวแลวจึงบอก method list() วาไฟลตวั นี้ควรเก็บไวใน list ประโยคที่แสดงผลโดยไมตองกําหนดเงื่อนไข ตองตรวจสอบกับ args.length ถาคานี้เปน 0 เราจะเก็บไฟลทก ุ ตัวไวใน array list ดวยการเรียกใช fileList = path.list(); แตถา มีการกําหนดเงื่อนไข เราจะสงเงื่อนไขนี้ไปให method accept() เพื่อทําการคัดเลือกไฟลทถ ี่ ูกตอง ตามเงื่อนไข ดวยประโยค fileList = path.list(new DirFilter(args[0])); สมมติวา args[0] ของเรามีคาเปน "te" (ดังตัวอยาง) "te" ก็จะถูกเก็บไวเปนตัวตรวจสอบวาไฟลที่อยูใน path มีคํานี้อยูห  รือไม เชนไฟลชื่อ Calculate.java Method list() กําหนดให parameter ทีส ่ งเขาไปเปน object จาก class FileNameFilter ดังนั้นเรา สามารถที่จะเขียน method accept() ในลักษณะใดก็ได ในที่นี้เราดึงเอาเฉพาะชื่อไฟลทไ ี่ มมี path รวมอยูด  วย ดวยการกําหนดดังนี้ String file = new File(name).getName();

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

210

หลังจากนั้นเราใช method indexOf() จาก class String ในการตรวจสอบวา "te" มีอยูในไฟลนี้หรือไม ซึ่งถามีคาที่ไดจาก indexOf() จะเปนตําแหนงที่ "te" อยู แตถาไมมีไดคา -1 เรานําคานี้มาเปรียบเทียบ กับ -1 เพื่อบอกให list() รูวาควรเก็บไฟลตัวนี้หรือไม (true = เก็บ false = ไมเก็บ) return file.indexOf(fileName) != -1; ไฟลทุกตัวที่เราไดจาก method list() จะถูกเก็บไวในตัวแปร fileList เพื่อเอาไวใชในการแสดงผลตอไป แตกอนที่เราจะแสดงผล เราทําการเรียงลําดับของไฟลใน fileList ดวยการเรียกใช method sort() ของ class Arrays โปรแกรมตัวนี้อาจดูเขาใจยากสักหนอย แตกไ ็ มยากเกินไปนัก ผูอานตองทําความเขาใจในเรื่องของการ เรียกใช method list() ที่มาจาก class File รวมไปถึงการเขียน code ตามขอกําหนดที่เราตองการใน method accept() สิ่งที่เราตองคํานึงถึง คือ Method list() ใน class File มีอยูสองตัว คือ ตัวที่ไมมี parameter และตัวที่มี parameter สําหรับ method ตัวที่มี parameter นี้ parameter ตองเปน object จาก class FileNameFilter ดังนัน ้ เราตอง สราง class ที่มาจาก class นี้พรอมทั้งทําการ override method accept() ใหทาํ งานตามที่เราตองการ ผูอานควรทดลอง run โปรแกรมตัวนีด ้ วยเงื่อนไขตาง ๆ เพื่อใหเกิดความเขาใจมากยิ่งขึ้น และควรทดลอง เขียน code ให method accept() ใหมโดยกําหนดใหทาํ การตาง ๆ ทีต ่ างออกไปจากที่เขียนในโปรแกรม ตัวอยางนี้ เราไดพูดถึงการแสดงรายการของไฟลที่มีอยูใ น directory การสรางเงื่อนไขใหกับ list() และ accept() พอสมควรแลว ตอไปเราจะพูดถึงการอาน การเขียน ไฟล โดยเราจะเริ่มตนที่ Input streams Input and Output streams (ชองทางการนําขอมูลเขา และ การนําขอมูลออก) Java กําหนดใหมีการนําขอมูลเขาสูโปรแกรมไดหลายทาง ซึ่งเราก็ไดสม ั ผัสถึงวิธีการมาบางพอสมควรใน เรื่องของการนําขอมูลเขาผานทางชองทางการนําเขามาตรฐาน (standard I/O) ตอไปนี้เราจะมาดูถึงการ นําขอมูลที่มาจากไฟลเขาสูโปรแกรม รูปแบบของขอมูลทีถ ่ ูกจัดเก็บในไฟลนั้นถูกแบงออกเปนสองลักษณะคือ 1. ขอมูลที่อยูในรูปแบบของ character เชน code ของโปรแกรมทีส ่ รางขึ้นจาก Text editor พูด งาย ๆ ก็คือ เราสามารถที่จะอานขอมูลเหลานีไ ้ ด เราเรียกไฟลแบบนี้วา text file 2. ขอมูลที่ถูกจัดเก็บในรูปแบบของ binary data เชนขอมูลทีถ ่ ก ู เก็บในรูปแบบของ MS Word เรา ไมสามรถที่จะอานขอมูลเหลานี้ไดตองอาศัยโปรแกรมในการชวยอาน เราเรียกไฟลในรูปแบบนี้ วา binary file เราจะเริ่มดวยการอานขอมูลจาก text file ที่เก็บ code ของโปรแกรมที่เราไดเขียนขึ้น //ReadingTextFile.java import java.io.*; class ReadingTextFile { //don't want to deal with error, let Java takes care of it public static void main(String[] args) throws IOException { BufferedReader in;//input buffer FileReader file; //input file String str; //string to store characters read from file file = new FileReader(args[0]); //open an input file in = new BufferedReader(file); //store contents in buffer int lineNo = 1;

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

}

}

Streams I/O

211

//keep reading from buffer until null is reached while((str = in.readLine()) != null) { System.out.println(lineNo + " " + str); lineNo++; } in.close(); //manually close the file

เราเปดไฟลที่ตอ  งการอานดวย FileReader() พรอมกับการเรียกใช BufferedReader() เพื่อใหการอาน ขอมูลทําไดรวดเร็วขึ้น เราอานขอมูลเขามาเก็บไวใน str ทีละหนึ่งแถวจนกวาขอมูลหมดจาก buffer หลังจากนั้นเราก็สงขอมูลที่อานไดออกไปยังหนาจอพรอมทัง้ เลขที่บรรทัด เมื่อสงขอมูลหมดแลวเราก็ปด ไฟลดวยการใช close() ผลลัพธที่เราไดจากการสงไฟล ReadingTextFile.java ไปใหโปรแกรมนี้ คือ 1 //ReadingTextFile.java 2 3 import java.io.*; 4 5 class ReadingTextFile { 6 //don't want to deal with error, let Java takes care of it 7 public static void main(String[] args) throws IOException { 8 BufferedReader in; //input buffer 9 FileReader file; //input file 10 String str; //string to store characters read from file 11 12 file = new FileReader(args[0]); //open an input file 13 in = new BufferedReader(file); //store contents in buffer 14 15 int lineNo = 1; 16 //keep reading from buffer until null is reached 17 while((str = in.readLine()) != null) { 18 System.out.println(lineNo + " " + str); 19 lineNo++; 20 } 21 in.close(); //manually close the file 22 } 23 } เรามาดูตัวอยางที่อานขอมูลดวยการใช FileInputStream() และ read() ในการอานกันบาง //ReadTextFile.java import java.io.*; class ReadTextFile { public static void main(String[] args) throws IOException { FileInputStream in; //file input stream int ch; //store each character read try { in = new FileInputStream(args[0]); while((ch = in.read()) != -1) { System.out.print((char)ch); } in.close(); }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

}

Streams I/O

212

//file not found catch(FileNotFoundException e) { System.err.println("Cannot find: " + args[0]); System.exit(1); } //no argument specified catch(ArrayIndexOutOfBoundsException e) { System.err.println("Usage: ReadTextFile file-name"); System.exit(1); }

}

โปรแกรมตัวนี้ใช FileInputStream() เปนตัวเปดไฟล และใช read() ในการอานขอมูลทีละ byte จาก FileInputStream ทําการจัดเก็บขอมูลที่อานไดไวใน ch พรอมทั้งสงขอมูลที่อานไดนี้ออกไปทางหนาจอ จนกวาการอานจะสิ้นสุดลง โดยอานเจอ -1 หรือ EOF (End Of File) ในการสงขอมูลที่อานไดออกไปยังหนาจอนั้น เราตองทําการ cast ใหกับ ch กอนมิเชนนั้นแลวขอมูลที่ สงออกไปจะไมตรงกับที่อานเขามา โปรแกรมของเรายังไดทําการตรวจจับ error ที่อาจเกิดขึ้นสองตัว คือ โปรแกรมหาไฟลไมเจอ และ ผูใ ชไมกําหนดชือ ่ ไฟลทใี่ ชเปนขอมูลสําหรับการเปดอาน หลังจากทดลอง run ดวยไฟล ReadTextFile.java ผลลัพธที่ไดคือ //ReadTextFile.java import java.io.*; class ReadTextFile { public static void main(String[] args) throws IOException { FileInputStream in; //file input stream int ch; //store each character read

}

}

try { in = new FileInputStream(args[0]); while((ch = in.read()) != -1) { System.out.print((char)ch); } in.close(); } //file not found catch(FileNotFoundException e) { System.err.println("Cannot find: " + args[0]); System.exit(1); } //no argument specified catch(ArrayIndexOutOfBoundsException e) { System.err.println("Usage: ReadTextFile file-name"); System.exit(1); }

character streams โดยทั่วไปเหมาะสมกับการอาน และเขียนขอมูลที่เปน text ดังนั้นหากจะเอามาใชกบ ั ขอมูลอื่น ๆ ก็จะสรางความยุงยากในการอานและเขียนมากพอสมควร ดังนัน ้ ในการอานและเขียนขอมูลที่ ไมใช text เราจึงตองใชการอานและเขียนขอมูลที่อยูใ นรูปแบบของ binary data แตกอนที่จะพูดถึงเรื่อง ของ Binary file เราจะมาดูกันถึงความยุงยากที่วา ในการทํางานกับ text file

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

213

โปรแกรม TextWithStreamTok.java อานขอมูลที่ถูกเก็บไวในรูปแบบของ text นํามาประมวลผล เสร็จ แลวจึงสงขอมูลกลับไปยังหนาจอ เพื่อใหผูอา นเขาใจงายขึน ้ เราจึงจัดเก็บขอมูลอยูใน format String

double int

เชน Notebook CoffeeMug PaperCutter

12.00 5.00 12.50

30 40 25

และเราจะกําหนดใหมีขอมูลเพียง 3 ตัวเทานั้น ลองมาดูการใช StreamTokenizer ที่เราไดพูดถึงตอนที่ เราอานขอมูลนําเขาจาก keyboard กอนหนานี้ วาจะนํามาใชกับขอมูลที่อยูในไฟลไดอยางไร ใน โปรแกรมตัวอยางดานลางนี้ //TextWithStreamTok.java - Reading text data from a file import java.io.*; class TextWithStreamTok { public static void main(String[] args) throws IOException { BufferedReader in = null; //input buffer FileReader file = null; //input file StreamTokenizer stream = null; //tokens try { file = new FileReader(args[0]); //get a file from argument-list in = new BufferedReader(file); //storage buffer //create tokens stream = new StreamTokenizer(in); stream.eolIsSignificant(true); //EOL counted but ignored } catch(FileNotFoundException e) { System.err.println("Cannot find file: " + args[0]); System.exit(1); } //arrays to store data only 3 items as example e.g. //description prices unit //Coffee-Mug 12.5 30 String[] descs = new String[3]; double[] prices = new double[3]; int[] units = new int[3]; int i = 0, j = 0, k = 0; //arrays' indices boolean first = true; //make sure correct data is read try { //reading tokens into corresponding arrays //until EOF is reached while(stream.nextToken() != StreamTokenizer.TT_EOF) { //data is a string if(stream.ttype == StreamTokenizer.TT_WORD) { descs[i++] = stream.sval; } //data is a number (price or unit) if(stream.ttype == StreamTokenizer.TT_NUMBER) { //first data in line is price

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

214

if(first == true) { prices[j++] = stream.nval; first = false; } //next one is unit price else { units[k++] = (int)stream.nval; first = true; }

} //ignore EOL if(stream.ttype == StreamTokenizer.TT_EOL) { /* do nothing */ }

} in.close();

//close the stream } //trouble reading file catch(IOException e) { System.err.println("Error reading file."); e.printStackTrace(); System.exit(1); } //too many items for arrays catch(ArrayIndexOutOfBoundsException e) { System.err.println("Array index out of bound."); e.printStackTrace(); System.exit(1); } }

}

display(descs, prices, units);

//display data

//display data to screen private static void display(String[] d, double[] p, int[] u) { double total = 0.00; for(int i = 0; i < d.length; i++) { total = p[i] * u[i]; System.out.print(d[i] + "\t" + p[i]); System.out.println("\t" + u[i] + "\t" + total); } }

การทํางานหลัก ๆ ของโปรแกรมก็คือ การอานขอมูลทีถ ่ ูกจัดเก็บใน format ที่ไดกลาวไว สิ่งสําคัญที่เรา ตองคํานึงถึงคือ ตําแหนงและชนิดของขอมูลที่เราตองอาน กอนอื่นเราตองกําหนดชองทางนําเขาขอมูล ดังนี้ file = new FileReader(args[0]); //get a file from argument-list in = new BufferedReader(file); //storage buffer //create tokens stream = new StreamTokenizer(in); stream.eolIsSignificant(true); //EOL counted but ignored หลังจากนั้นเราก็ตรวจสอบ token ที่เราอานจาก stream วาเปนตัวเลขหรือวาเปน string while(stream.nextToken() != StreamTokenizer.TT_EOF) { //data is a string

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

}

Streams I/O

215

if(stream.ttype == StreamTokenizer.TT_WORD) { descs[i++] = stream.sval; } //data is a number (price or unit) if(stream.ttype == StreamTokenizer.TT_NUMBER) { //first data in line is price if(first == true) { prices[j++] = stream.nval; first = false; } //next one is unit price else { units[k++] = (int)stream.nval; first = true; } } //ignore EOL if(stream.ttype == StreamTokenizer.TT_EOL) { /* do nothing */ }

เราจะเก็บขอมูลที่เปน string ไวใน descs[] ขอมูลที่เปน double ไวใน prices[] และขอมูลที่เปน int ไว ใน units[] สิ่งที่เราตองคํานึงก็คือ ลําดับของขอมูลที่เปนตัวเลข เรารูวาตัวเลขกลุมแรกทีอ ่ านไดคือ prices และขอมูลถัดไปคือ units ดังนั้นเราตองใชตัวแปร first เปนตัวกําหนดที่เก็บขอมูลวา ที่อานไดครั้ง แรกควรไปอยูท  ี่ prices[] และที่อานไดถัดมาควรไปอยูท  ี่ units[] และเมื่อเราอานจนหมดแลวเราก็สง arrays ทั้งสามตัวไปให display() ทําการประมวลผล และแสดงผลตอไป ผลลัพธที่เราได จากการ run คือ >java TextWithStreamTok data.dat Notebook 12.0 30 360.0 CoffeeMug 5.0 40 200.0 PaperCutter 12.5 25 312.5 ขอมูลที่เก็บไวในไฟล data.dat จะตองมีชองวางระหวางขอมูลแตละตัว เชน Notebook 12.0 30 CoffeeMug 5.0 40 PaperCutter 12.5 25 หรือจะใหอยูใ นบรรทัดเดียวกันก็ได เชน Notebook 12.0 30 CoffeeMug 5.0 40 PaperCutter 12.5 25 ทั้งนี้เพราะ nextToken() จะอานขอมูลที่อยูถ  ด ั จากชองวางไปจนกวาจะเจอชองวางอีกครั้งหนึ่ง จะเห็นไดวาเราตองคอยระวังการอานขอมูล เพราะถาลําดับของการอานขอมูลผิด โปรแกรมของเราก็จะ เกิดความผิดพลาด และที่สําคัญอีกอยางหนึ่งคือ ขั้นตอนทีย ่ งุ ยากของการกําหนดลําดับของขอมูล การ อานขอมูล (ลองนึกถึงการอาน ถาเรามีขอมูลที่เปนตัวเลขอยูม  ากกวาสองตัว และมีขอมูลที่เปน string อยู ระหวางขอมูลเหลานี้) ดังนั้นเราจึงไมนิยมใช text file ในการเก็บขอมูลที่เปน primitive type เราควรใช text file ในการทํางานกับขอมูลที่เปน text เทานั้น ตัวอยางตอไปเปนการใช StreamTokenizer นับจํานวนของคําทีม ่ ีอยูในไฟล เพื่อที่จะแสดงใหเห็นวาถา ขอมูลเปน text ทั้งหมดการทํางานจะไมมีปญหาเทาไร //WordCount.java - Using StreamTokenizer to count word

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

216

import java.io.*; class WordCount { public static void main(String[] args) throws IOException { //exit if there's no file specified if(args.length < 1) { System.out.println("Usage: WordCount file-name."); System.exit(1); } FileReader inFile = null; //file stream StreamTokenizer stream = null; //tokens stream int count = 0; //number of words in the file

}

}

try { inFile = new FileReader(args[0]); stream = new StreamTokenizer(inFile); count = wordCount(stream); System.out.println(count + " words counted in " + args[0]); } catch(FileNotFoundException e) { System.err.println("Cannot find: " + args[0]); e.printStackTrace(); System.exit(1); } finally { //close the file if(inFile != null) { try { inFile.close(); } catch(IOException e) { /* do nothing */ } } }

//method to count word in the stream private static int wordCount(StreamTokenizer s) throws IOException { int count = 0; try { while(s.nextToken() != StreamTokenizer.TT_EOF) { //count only word if(s.ttype == StreamTokenizer.TT_WORD) count++; } } catch(IOException e) { System.err.println("Error reading stream: " + s); e.printStackTrace(); System.exit(1); } return count; }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

217

โปรแกรม WordCount.java ทําการนับจํานวนของคําที่ปรากฏอยูในไฟลทม ี่ าจาก command-line argument โดยเรียกใช StreamTokenizer เปนตัวตรวจสอบวา ขอมูลที่มีอยูในไฟลเปน string หรือไม ถาเปนก็จะนับ โดยไมสนใจถึงรูปแบบของ string นั้น ๆ เชน "s13" ก็นับเปน string โปรแกรม WordCount.java ของเราตัวนีใ้ ช object จาก FileReader เปนตัวกําหนดชองทางผานไปยัง StreamTokenizer โดยตรง ซึง่ ตางจากตัวอยางกอนหนานี้ ที่เราใช BufferedReader เปนที่เก็บขอมูล การใช FileReader โดยตรงจะทําใหเสียเวลาในการประมวลผลมากถาไฟลมีขนาดใหญ เพราะฉะนั้นถา ผูอานตองการความเร็วในการประมวลผล ก็ตอ  งใช BufferedReader เปนตัวเก็บขอมูลทีต ่ องการ ประมวลผล เราไดทดลอง run โปรแกรมดวยไฟลของ Windows Xp Æ vbe6.dll ซึ่งมีขนาดเทากับ 2,498,560 bytes ผลลัพธที่ไดกอนและหลังการใช BufferedReader คือ >java WordCount vbe6.dll Start: Fri Feb 28 10:08:52 GMT+07:00 2003 279829 words counted in vbe6.dll Stop: Fri Feb 28 10:08:54 GMT+07:00 2003 >java WordCount vbe6.dll Start: Fri Feb 28 10:10:35 GMT+07:00 2003 279829 words counted in vbe6.dll Stop: Fri Feb 28 10:10:36 GMT+07:00 2003 จะเห็นวาการประมวลผลดวยการใช BufferedReader ใชเวลานอยกวาการใช FileReader โดยตรง (ดีขึ้น ประมาณ 1 วินาที) เราใชการวัดหาเวลาอยางงาย ๆ ดวยการใช Date เปนตัวบอกถึงความแตกตางกอน และหลังการอานขอมูลในไฟล โดยเปลี่ยนแปลง code บางสวนดังนี้ … BufferedReader buf = null; …

//buffer holding data

try { System.out.println("Start: " + new Date()); inFile = new FileReader(args[0]); buf = new BufferedReader(inFile); stream = new StreamTokenizer(buf); … … … finally { //close the file if(inFile != null) { try { inFile.close(); } catch(IOException e) { /* do nothing */ } } //close stream if(buf != null) { try { buf.close(); System.out.println("Stop: " + new Date()); } catch(IOException e) { /* do nothing */ } } … …

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

218

อีกสิ่งหนึ่งที่เราไดพูดถึงกอนหนานี้ แตไมเคยไดใชเลยก็คือ finally เพื่อแสดงใหดูถึงประโยชนของ finally เราจึงใช finally เปนตัวปดไฟลในโปรแกรมใหเรา ผูอ  านควรใช finally เปนตัวปดไฟลเสมอ (โปรแกรมตัวอยางในบทนี้หลาย ๆ ตัว อาจไมใช finally เปนตัวปดไฟล แตนั่นไมไดหมายความวา ผูอาน จะใชไมได) ถาผูอานตองการทีจ ่ ะจับเวลาการทํางานของโปรแกรม หรือสวนของโปรแกรม Java มี method อีกตัว หนึ่งทีผ ่ ูอานสามารถเรียกใชไดนั่นก็คือ method currentTimeMillis() ดังตัวอยางการใชที่แสดงไว ดานลางนี้ //ElapsedTime.java class ElapsedTime { public static void main(String[] args) { long startTime, stopTime; //get starting time startTime = System.currentTimeMillis(); //do some looping for(int i = 0; i < 100000; i++) for(int j = 0; j < 100000; j++) ; //get ending time stopTime = System.currentTimeMillis(); //calculate elapsed time double elapsedTime = (double)(stopTime - startTime) / 1000.0;

}

}

System.out.print("Elapsed time: "); System.out.println(elapsedTime + " seconds.");

ผลลัพธที่ไดจากการ run คือ Elapsed time: 85.093 seconds. โปรแกรม ElapsedTime.java เรียกใช currentTimeMillis() กอนและหลังจากการใช loop หลังจากนั้นก็ หาเวลาที่ใชไปดวยการนําเอาเวลาเริ่มตนไปลบออกจากเวลาที่ไดหลังจากการใช loop เราสามารถทีจ ่ ะทําใหการทํางานกับขอมูลที่เปน text ไดงายขึ้นถาเรากําหนดใหมี ตัวแบงขอมูล (delimiter) ระหวางขอมูลแตละตัวที่อยูใ นไฟล ซึ่งตัวแบงที่วานี้จะเปนตัวอักษรใด ๆ ก็ไดที่ไมมส ี วน เกี่ยวของกับขอมูลที่อยูใ นไฟล เชน เราอาจใชเครื่องหมาย "|" เปนตัวแบงขอมูลในไฟลตัวอยางที่ไดพด ู ถึงกอนหนานี้ ลองมาดูตวั อยางการใชตัวแบงที่วานี้กัน //TokenWithDelimiter.java - Using '|' as delimiter in a text file import java.io.*; import java.util.StringTokenizer; import java.lang.Integer; class TokenWithDelimiter { public static void main(String[] args) throws IOException { //data to write to file String[] items = {"Notebook", "Coffee Mug", "Paper cutter"}; double[] prices = {12.0D, 5.0D, 12.5D};

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

219

int[] units = {30, 40, 25}; //check to see if a file is provided if(args.length < 1) { System.err.println("Usage: TokenWithDelimeter filename."); System.exit(1); } writeToFile(args[0], items, prices, units); processData(args[0]); } //writing data in arrays to a given file private static void writeToFile(String fileName, String[] items, double[] prices, int[] units) throws IOException { File dataFile = null; FileWriter fWriter = null; BufferedWriter buffer = null; PrintWriter out = null; try { dataFile = new File(fileName); fWriter = new FileWriter(dataFile); buffer = new BufferedWriter(fWriter); out = new PrintWriter(buffer); //printing data to file with '|' in between for(int i = 0; i < items.length; i++) { out.print(items[i]); out.print('|'); out.print(prices[i]); out.print('|'); out.println(units[i]); }

}

} catch(IOException e) { System.err.println("Error writing to file"); e.printStackTrace(); System.exit(1); } finally { if(out != null) out.close(); }

//reading data from a given file & display to screen private static void processData(String fileName) throws IOException { String item; //item read double price; //price read int unit; //unit read File dataFile = null; FileReader fReader = null; BufferedReader buffer = null; String input = null; try {

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

220

dataFile = new File(fileName); fReader = new FileReader(dataFile); buffer = new BufferedReader(fReader); input = buffer.readLine(); //read first line of data //keep reading until there's no more lines to read while(input != null) { //get token from input-line - skip '|' StringTokenizer token = new StringTokenizer(input, "|"); item = token.nextToken(); price = Double.parseDouble(token.nextToken()); unit = Integer.parseInt(token.nextToken()); //display to screen System.out.print(item + "\t" + price + "\t" + unit); System.out.println("\t" + price * unit); input = buffer.readLine(); }

}

}

} catch(IOException e) { System.err.println("Error reading file"); e.printStackTrace(); System.exit(1); } finally { if(buffer != null) buffer.close(); }

เราใชเครื่องหมาย '|' ในการแบงขอมูลที่อยูในไฟล พรอมทัง้ ใช class StringTokenizer เปนตัวดึงขอมูล ที่อานมาจากไฟล หลังจากที่เราเขียนขอมูลที่อยูใน arrays ทั้งสามตัวไปเก็บไวในไฟลดว ยการใช print() และ println() ผูอานควรสังเกตถึงการเขียนขอมูลในแตละครั้งวา เราเขียน '|' ตามหลังเสมอ ยกเวนการ เขียนขอมูลตัวสุดทาย dataFile = new File(fileName); fWriter = new FileWriter(dataFile); buffer = new BufferedWriter(fWriter); out = new PrintWriter(buffer); //printing data to file with '|' in between for(int i = 0; i < items.length; i++) { out.print(items[i]); out.print('|'); out.print(prices[i]); out.print('|'); out.println(units[i]); } หลังจากนั้นเราก็อานขอมูลกลับออกมาดวย readLine() เราทําการดึงขอมูลแตละตัวทีถ ่ ูกแบงดวย '|' ดวย การใช nextToken() แตกอนที่เราจะทําการดึงขอมูลทุกครัง้ ในแตละบรรทัด เราจะตองกําหนดเงื่อนไขให token ของเราเสียกอน ดวยการใช StringTokenizer token = new StringTokenizer(input, "|"); เพื่อที่จะบังคับใหการดึงขอมูลนั้นเกิดขึ้นระหวางเครื่องหมาย '|' ขอมูลตัวแรกที่เราดึงออกมาเปน String เราจึงไมตองแปลงขอมูลตัวนี้ แตขอมูลอีกสองตัวที่เราดึงออกเปน double และ int ที่ถูกเก็บใหเปน

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

221

String ในการเขียน ดังนั้นเราจึงตองแปลงขอมูลทั้งสองตัวนี้ หลังจากที่เราไดขอมูลทั้งสามตัวแลวเราก็ แสดงผลออกไปยังหนาจอ dataFile = new File(fileName); fReader = new FileReader(dataFile); buffer = new BufferedReader(fReader); input = buffer.readLine(); //read first line of data //keep reading until there's no more lines to read while(input != null) { //get token from input-line - skip '|' StringTokenizer token = new StringTokenizer(input, "|"); item = token.nextToken(); price = Double.parseDouble(token.nextToken()); unit = Integer.parseInt(token.nextToken()); //display to screen System.out.print(item + "\t" + price + "\t" + unit); System.out.println("\t" + price * unit); input = buffer.readLine(); } ในการเขียนไฟลของเราครั้งนี้เราใช PrintWriter เปนตัวชวย ซึ่งภายใน class PrintWriter นี้เราสามารถที่ จะเรียกใช print() และ println() ได ทําใหการเขียนขอมูลสงไปยังไฟลของเราเหมือนกับการเขียนที่เรา ไดทํามากอนหนานี้ตอนที่เราสงขอมูลไปยังหนาจอ แตเราจะตองใช PrintWriter รวมกับ FileWriter เพื่อใหการเขียนไปยังไฟลทําได และ BufferedWriter เพื่อใหทาํ ไดอยางมีประสิทธิภาพ (การใช buffer จะชวยใหการทํางานกับขอมูลไวขึ้น) ผลลัพธที่ไดจากการ run >java TokenWithDelimiter tokens.dat Notebook 12.0 30 360.0 Coffee Mug 5.0 40 200.0 Paper cutter 12.5 25 312.5 Binary file ในการเขียน binary data เขาสูไฟลนั้นเราจะตองคํานึงถึงวิธก ี ารในการที่จะเขียนขอมูล เพราะในการเขียน ขอมูลเขาสูไฟลนั้น มีผลตอการอานขอมูลกลับออกมา ลําดับของขอมูลทีเ่ ขียนเขาสูไฟล จะตองอานกลับ ออกมาดวยขั้นตอนเดียวกัน ในการเขียนขอมูลที่เปน binary data นั้น เราสามารถที่จะเลือกใช method หลาย ๆ ตัวที่ Java มีใหเปน ตัวชวยในการเขียน เชน Method writeBoolean(boolean) writeShort(int) writeInt(int) writeLong(long) writeFloat(float) writeDouble(double) writeChar(int) writeChars(String) writeUTF(String)

Throws IOException IOException IOException IOException IOException IOException IOException IOException IOException

ความหมาย เขียนคาของ boolean จํานวน 1 byte เขียนคาของ short จํานวน 2 byte เขียนคาของ int จํานวน 4 byte เขียนคาของ long จํานวน 8 byte เขียนคาของ float จํานวน 4 byte เขียนคาของ double จํานวน 8 byte เขียนคาของ char จํานวน 2 byte เขียน String จํานวน 2 byte ตอ 1 ตัวอักษร เขียน String จํานวน 1 byte ตอตัวอักษร บวกอีก 2 byte สําหรับคาของความยาวของ String

สําหรับการอานนั้น เราจะใช method นี้

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Method readBoolean() readShort() readInt() readLong() readFloat(0 readDouble() readChar() readUTF() skipBytes(int)

Streams I/O

Throws EOFException EOFException EOFException EOFException EOFException EOFException EOFException EOFException EOFException

222

ความหมาย อาน 1 byte สงคา boolean กลับ อาน 2 byte สงคา Short กลับ อาน 4 byte สงคา int กลับ อาน 8 byte สงคา long กลับ อาน 4 byte สงคา float กลับ อาน 8 byte สงคา double กลับ อาน 2 byte สงคา char กลับ อาน String UTF ไมอานขอมูลจํานวนเทากับ byte ที่กําหนด

ตัวอยางตอไปจะเปนตัวอยางการเขียนขอมูลเขาสูไฟลในรูปแบบของ binary data หลังจากนั้นจะอาน กลับออกมา เราจะเริ่มตนดวยการสราง record จํานวน 3 ตัว สรางไฟลสําหรับเก็บ record เหลานี้ อาน record ออกมาทีละตัว ประมวล พรอมทั้งแสดงผลไปยังหนาจอ Record คือกลุม  ขอมูลที่ประกอบไปดวยขอมูลตาง ๆ ซึ่งอาจเปนขอมูลชนิดเดียวกันหรือขอมูลตางชนิดกัน ก็ได ใน Java เราสราง record ดวยการใช class เปนตัวสราง เราจะกําหนดให record ของเรามี ขอมูล อยู 3 field เหมือนกับตัวอยางกอนหนานี้ คือ 1. description 2. price 3. unit เรามาดูโปรแกรมตัวอยางกันดีกวา //DataFile.java - Sequential Access file import java.io.*; class DataFile { public static void main(String[] args) throws IOException { FileOutputStream fout; //file output stream DataOutputStream dout; //data output stream FileInputStream fin; //file input stream DataInputStream din; //data input stream //setting up data to be written to a file String[] desc = {"Coffee Mug", "Bookmark", "Note book"}; double[] prices = {5.00, 2.00, 10.00}; int[] unit = {12, 50, 30}; //variables storing data read from file String description; double price, total = 0.00; int unitPrice; //open file for writing try { fout = new FileOutputStream(args[0]); dout = new DataOutputStream(fout); for(int i = 0; i < desc.length; i++) { dout.writeUTF(desc[i]); dout.writeDouble(prices[i]); dout.writeInt(unit[i]); } dout.close();

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

223

} catch(FileNotFoundException e) { System.err.println("Cannot open " + args[0]); return; } catch(ArrayIndexOutOfBoundsException e) { System.err.println("Usage: DataFile file-name."); return; }

}

}

//open file for input try { fin = new FileInputStream(args[0]); din = new DataInputStream(fin); System.out.println("Description\tPrice\tUnit\tTotal"); while(true) { description = din.readUTF(); price = din.readDouble(); unitPrice = din.readInt(); total = price * unitPrice; display(description, price, unitPrice, total); } } catch(EOFException e) { //use this exception to stop the while loop //and exit the program System.exit(1); } catch(IOException e) { System.err.println("Error reading file: " + e.toString()); System.exit(1); }

//display a record to screen public static void display(String d, double p, int u, double t) { System.out.println(d+"\t"+p+"\t"+u+"\t"+t); }

โปรแกรมของเราใช DataOutputStream และ DataInputStream เปนตัวสงขอมูลไปเก็บไวที่ไฟล และ เราใช for loop เปนตัวกําหนดจํานวนครั้งของการเขียน fout = new FileOutputStream(args[0]); dout = new DataOutputStream(fout); for(int i = 0; i < desc.length; i++) { dout.writeUTF(desc[i]); dout.writeDouble(prices[i]); dout.writeInt(unit[i]); } หลังจากนั้นเราก็อานขอมูลออกมาจากไฟล ตามลําดับ ถาเราลองเปดดูไฟลที่เก็บขอมูลที่เราสรางขึ้น เรา จะไมสามารถอานได เพราะขอมูลเหลานี้ถูกเก็บอยูในรูปแบบของ binary data ในการอานขอมูลออกมาจากไฟลนั้นเราใช while loop ในการอานดวยการกําหนดใหเปน infinite loop โดยเราจะใช error ที่เกิดขึ้นเปนตัวยุติการทํางานของ loop เนื่องจากวาเรารูวาในการอานขอมูลออกจาก ไฟลนั้น ในที่สด ุ เราก็จะอานเจอเครื่องหมายทีบ ่ งบอกถึงจุดจบของไฟล (EOF) ซึ่งอาจเปนการเขียน code ที่ไมคอยจะสวยเทาไร แตกท ็ าํ ใหการทํางานของโปรแกรมเปนไปตามที่เราตองการ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

224

fin = new FileInputStream(args[0]); din = new DataInputStream(fin); System.out.println("Description\tPrice\tUnit\tTotal"); while(true) { description = din.readUTF(); price = din.readDouble(); unitPrice = din.readInt(); total = price * unitPrice; display(description, price, unitPrice, total); } ผลลัพธที่ไดจากการ run คือ >java DataFile data.dat Description Coffee Mug Bookmark Note book

Price 5.0 2.0 10.0

Unit 12 50 30

Total 60.0 100.0 300.0

จากผลลัพธที่ไดจะเห็นวาการจัดเรียงของขอมูลทีส ่ งไปยังหนาจอ ยังดูไมเรียบรอยและสวยงามเทาไร ถา ตองการใหการแสดงผลอยูในรูปแบบที่สวยงาม เราจะตองสราง class ขึ้นมาใชเองดวยการ extends class ที่เราสรางขึ้นจาก class PrintWritter พรอมกับทําการสราง method output() ทีท ่ ําการแสดงผล ขอมูลดวยการจัดเรียงทางขวา และทําการ override method print() และ println() เราจะสราง class FormatWriter ดังที่แสดงใหดูในโปรแกรมตัวอยางที่ไดดด ั แปลงมาจากโปรแกรม DataFile.java //DataFile.java - Sequential Access file //-(modified for formatted output) import java.io.*; //for pretty printing (formatted - right justified) class FormatWriter extends PrintWriter { private int width = 10; //default constructor FormatWriter(Writer output) { super(output); } //constructor with specified width FormatWriter(Writer out, int width) { super(out); this.width = width; } //set prefer output style private void output(String str) { //calculate spaces int blanks = width - str.length(); //fill with blanks before actual data for(int i = 0; i < blanks; i++) super.print(' '); //print data super.print(str); }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

225

//our print() and println() methods with different types of data public void print(String str) { output(str); } public void println(String str) { output(str); super.println(); } public void print(double value) { output(String.valueOf(value)); } public void print(int value) { output(String.valueOf(value)); }

}

public void println(double value) { this.print(value); super.println(); }

class DataFile { public static void main(String[] args) throws IOException { FileOutputStream fout; //file output stream DataOutputStream dout; //data output stream FileInputStream fin; //file input stream DataInputStream din; //data input stream //setting up data to be written to a file String[] desc = {"Coffee Mug", "Bookmark", "Note book"}; double[] prices = {5.00, 2.00, 10.00}; int[] unit = {12, 50, 30}; double[] total = new double[3]; //open file for writing try { fout = new FileOutputStream(args[0]); dout = new DataOutputStream(fout); for(int i = 0; i < desc.length; i++) { dout.writeUTF(desc[i]); dout.writeDouble(prices[i]); dout.writeInt(unit[i]); } dout.close(); } catch(FileNotFoundException e) { System.err.println("Cannot open " + args[0]); return; } catch(ArrayIndexOutOfBoundsException e) { System.err.println("Usage: DataFile file-name."); return; } //open file for input //reuse variables desc, prices, and unit //calculate total fro each data item

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

}

}

Streams I/O

226

try { fin = new FileInputStream(args[0]); din = new DataInputStream(fin); boolean endOfFile = false; //EOF marker int index = 0; //array index while(!endOfFile) { try { //store data in arrays before printing desc[index] = din.readUTF(); prices[index] = din.readDouble(); unit[index] = din.readInt(); total[index] = prices[index] * unit[index]; index++; } catch(EOFException e) { endOfFile = true; //stop while loop din.close(); //close the file } } //display data - right justified display(desc, prices, unit, total); } catch(IOException e) { System.err.println("Error reading file: " + e.toString()); System.exit(1); }

//display a record to screen private static void display(String[] d, double[] p, int[] u, double[] t) { //create object from FileWriter with width of 12 FormatWriter out = new FormatWriter( new BufferedWriter( new FileWriter(FileDescriptor.out)), 12); //display header out.print("Description"); out.print("Prices"); out.print("Unit"); out.println("Total"); //display contents of arrays for(int i = 0; i < d.length; i++) { out.print(d[i]); out.print(p[i]); out.print(u[i]); out.println(t[i]); } out.close(); //close the stream }

เราสราง class FormatWriter ขึ้นมาใหมจาก class PrintWriter พรอมทั้งกําหนดใหมี constructor 2 โดยที่ตัวแรกเปน default constructor ที่มีหนาที่เรียก constructor ของ class PrintWriter สําหรับการ กําหนดชองทางผานออกของขอมูล สวนตัวที่สองเรากําหนดใหมค ี วามกวางของเนื้อที่ของขอมูลที่ ตองการแสดง FormatWriter(Writer out, int width) { super(out);

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

}

Streams I/O

227

this.width = width;

เราจะใช width ในการกําหนดจํานวนของชองวางที่เราตองการแสดงกอนการแสดงขอมูลจริง เชน ถาเรา กําหนดให width มีคาเปน 10 และขอมูลที่ตอ  งการแสดงมีคา เปน 2 ตัวอักษรเราก็จะทําการเขียนชองวาง จํานวนเทากับ 8 ตัว เสร็จแลวจึงเขียนขอมูลตามชองวางเหลานี้ เราทําไดดวยการเขียน method output() ใหทาํ การคํานวณหาจํานวนชองวางที่วา เมื่อไดแลวจึงสงไปยังหนาจอดวยการเรียก print() ของ class PrintWriter หลังจากนั้นจึงสงขอมูลจริงออกไป Method output() จะถูกเรียกใชใน print() และ println() ทีเ่ ราเขียนขึ้นมารองรับขอมูลตางชนิดกัน ซึ่ง ในที่นี้เรามีขอมูลเพียงสามชนิด คือ string double และ int การเขียน print() และ println() ก็ไมยาก ดังนี้ public void print(int value) { output(String.valueOf(value)); } public void println(double value) { this.print(value); super.println(); } เราเพียงแตเรียก output() ดวยคาที่ตองการแสดงผล แตเราจะตองเปลีย ่ นคานี้ใหอยูในรูปแบบของ string กอนที่จะสงคานี้ไปให output() เราเปลี่ยน display() ของเราใหมดวยการรับ parameter ที่เปน array แทนที่จะเปนขอมูลเดี่ยว ๆ เหมือน ที่ทาํ กอนหนานี้ พรอมทั้งประกาศตัวแปรจาก class FormatWriter ที่เราเขียนขึ้น ดังนี้ private static void display(String[] d, double[] p, int[] u, double[] t) { //create object from FileWriter with width of 12 FormatWriter out = new FormatWriter( new BufferedWriter( new FileWriter(FileDescriptor.out)), 12); //display header out.print("Description"); out.print("Prices"); out.print("Unit"); out.println("Total"); //display contents of arrays for(int i = 0; i < d.length; i++) { out.print(d[i]); out.print(p[i]); out.print(u[i]); out.println(t[i]); } out.close(); //close the stream } เพื่อใหการสงขอมูลออกทาง standard output เปนไปได เราตองสราง object จากสมาชิกที่ชื่อ out ของ class FileDescriptor (สมาชิกของ FileDescriptor มีอยูสามตัวคือ in out และ err ซึ่งหมายถึง ชองทางของ input output และ error ตามลําดับ) หลังจากนั้นเราก็สง object ตัวนี้ไปให BufferedWriter เพื่อสราง buffer สําหรับรองรับขอมูลทีจ ่ ะเกิดขึ้น และ buffer ตัวนี้จะเปน parameter ตัวแรกทีถ ่ ูกสงไปให constructor ของ FormatWriter และ 12 (ซึ่งเปน width) จะถูกสงไปเปน parameter ตัวที่สอง ทําให object out ของเราสามารถใชชอ  งทางผานออกได หลังจากนัน ้ เราก็แสดง ขอมูลดวยการเรียกใช print() และ println() ผาน object ตัวนี้

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

228

ในตัว main() ของเรา เราเปลี่ยนแปลง code ใหทาํ การอานขอมูลมาเก็บไวใน array สําหรับการสงไป แสดงผลใน display() … … boolean endOfFile = false; //EOF marker int index = 0; //array index while(!endOfFile) { try { //store data in arrays before printing desc[index] = din.readUTF(); prices[index] = din.readDouble(); unit[index] = din.readInt(); total[index] = prices[index] * unit[index]; index++; } catch(EOFException e) { endOfFile = true; //stop while loop din.close(); //close the file } } //display data - right justified display(desc, prices, unit, total); … … เรายังใช EOF error เปนตัวยุติการทํางานของ loop เหมือนเดิม เพียงแตแทนทีจ ่ ะใชคา -1 เราก็เลือกที่ จะใชตัวแปร boolean เปนตัวกําหนดการทํางานของ loop แทน ผลลัพธที่ไดจากการ run คือ >java DataFile data.dat Description Coffee Mug Bookmark Note book

Prices 5.0 2.0 10.0

Unit 12.0 50.0 30.0

Total 60.0 100.0 300.0

เรายังสามารถที่จะทําการแสดงผลที่อยูใ นรูปแบบที่เราตองการ ไดอีกหลายรูปแบบ ซึ่งก็ตองขึ้นอยูกับ ผูเขียนโปรแกรมวาตองการใหผลลัพธออกมาในลักษณะไหน ผูอานคงตองใชเวลาพอสมควรในการศึกษา และทดลองเขียน code ทีท ่ ําใหการแสดงผลมีความสวยงามมากขึ้น ตัวอยางตอไปนี้จะเปนการแสดงถึงความแตกตางในการใช writeUTF() กับการใช writeChars() //WriteCharsAndWriteUTF.java - Differences between the to methods import java.io.*; class WriteCharsAndWriteUTF { public static void main(String[] args) throws IOException { File f = new File(args[0]); DataOutputStream out = new DataOutputStream( new BufferedOutputStream( new FileOutputStream(f))); out.writeUTF("If it does not work, blame the computer."); int utfSize = out.size();

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

229

out.writeChars("If it does not work, blame the computer."); int charsSize = out.size() - utfSize;

}

}

out.close(); System.out.println("writeUTF() writes " + utfSize + " bytes."); System.out.println("writeChars writes " + charsSize + " bytes.");

ผลลัพธที่ไดจากการ run คือ >java WriteCharsAndWriteUTF difs.dat writeUTF() writes 42 bytes. writeChars writes 80 bytes. โปรแกรมของเราเขียน string จํานวน 40 ตัวอักษรไปยังไฟลดวยการใช writeUTF() และ writeChars() จากผลของการ run จะเห็นวา writeUTF() ใชเพียงแค 1 byte ตอตัวอักษรบวกกับอีก 2 byte สําหรับเก็บ ความยาวของ string สวน writeChars() ใช 2 byte ตอตัวอักษร การสรางและใช Random-access file ตัวอยางกอนหนานี้เราเขาหาขอมูลในไฟลแบบ กอน-หลัง หรือที่เรียกวา sequential access ซึ่งเปน วิธีการทีค ่ อนขางที่จะใชเวลามาก ถาขอมูลมีอยูเปนจํานวนมาก มีวิธีการอีกวิธีหนึ่งทีท ่ ําใหการเขาหา หรือ คนหาขอมูลทําไดรวดเร็ว นั่นก็คือการเขาหาแบบที่ไมตองเขาหาตามลําดับ กอน-หลัง หรือที่เรียกวา Random-access คําวา random-access ในที่นห ี้ มายความวาขอมูลที่ถูกดึงออก หรือ นําเขาไมมีสวนเกี่ยวของกับขอมูลที่ ถูกดึงออก หรือ นําเขากอนหนานี้ เชน ในการคนหาเบอรโทรศัพทของใครสักคนผานทาง operator ผู คนหา ณ เวลาปจจุบันไมมีความเกี่ยวของหรือความสัมพันธใด ๆ กับการคนหาทีผ ่ านมากอนหนา ในการจัดการกับขอมูลของ random-access file นั้นจะใชตัวชี้ตําแหนง (logical pointer) เปนตัวกําหนด ตําแหนงของการนําขอมูล เขา-ออก ซึ่งการกําหนดตําแหนงจะคํานวณจากจุดเริ่มตนของไฟล (ไมใช ตําแหนงที่เก็บจริงในหนวยความจําสํารอง) เราเรียกระยะทางจากจุดเริ่มตนนี้วา offset Java กําหนดการ เขาหาตําแหนงเหลานี้ดวยการใชคาํ สั่ง seek เพราะฉะนั้นในการเขาหาขอมูล ถาเรารูขนาดของขอมูลที่ ตายตัว (fixed length record) เราก็สามารถเขาหาขอมูล ณ ตําแหนง p ดวย p * length เราจะเริ่มตนดวยการสราง record ตัวอยาง โดยกําหนดให record ของเราประกอบดวย ชื่อ (first name) นามสกุล (last name) ปที่เกิด (year of birth) เงินเดือน (salary) เราจะกําหนดให record เกิดจาก class ที่มส ี มาชิกดังที่กลาวขางตน พรอมกับ method ตาง ๆ ที่ เกี่ยวของกับการทํางานกับ record นั้น ๆ //RandomAccessFileDemo.java import java.io.RandomAccessFile; import java.io.*; class RandomAccessFileDemo { public static void main(String[] args) throws IOException { //data to be written to a file

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

230

String[] names = {"John", "Paul", "Stephen", "Hendrix"}; String[] lasts = {"Kawakami", "Collins", "Anderson", "McCoy"}; int[] years = {1965, 1978, 1985, 1972}; double[] pays = {2400.0, 500.0, 5000.0, 9500.0}; //use to randomly select the position in a file //to write to/read from e.g. random[0] is at the second //position, random[2] is at the frist position etc. int []random = {2, 3, 0, 1}; //writing to a file RandomAccessFile f = new RandomAccessFile("emp.dat", "rw"); try { for(int i = 0; i < 4; i++) { Employee emp = new Employee(names[i], lasts[i], years[i], pays[i]); emp.write(f, random[i]); } } catch(IOException e) { System.err.println("Error writing file"); e.printStackTrace(); System.exit(1); } finally { if(f != null) { f.close(); } }

}

}

//reading from a file RandomAccessFile fin = null; try { fin = new RandomAccessFile("emp.dat", "r"); Employee em = new Employee(); System.out.println("Number of records = " + em.size(fin) + "\n"); for(int i = 0; i < 4; i++) { em.read(fin, random[i]); System.out.print("Record #" + (i+1) + ": "); em.show(); } } catch(IOException e) { System.err.println("Error reading file"); e.printStackTrace(); System.exit(1); } finally { if(fin != null) fin.close(); }

โปรแกรมตัวอยางของเราใช array 4 ตัวเปนตัวเก็บ record ที่ตองการเขียนไปยังไฟล และเพื่อเปนการ แสดงใหเห็นถึงการเขาหาไฟลในรูปแบบของความเปน random เราจึงใช array random เปนตัวกําหนด ถึงตําแหนงของ record ที่เราตองการจะเขียน ซึ่งเราไดกําหนดให

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Record Record Record Record

ตัวแรกเขียนในตําแหนงที่ 2 ตัวที่สองเขียนในตําแหนงที่ 3 ตัวที่สามเขียนในตําแหนงที่ 0 ตัวที่สด ุ ทายเขียนในตําแหนงที่ 1

Streams I/O

231

(random[0]) (random[1]) (random[2]) (random[3])

เราเก็บขอมูลเหลานี้ดว ยการสราง object จาก class Employee ซึ่งเปน class ที่ทําหนาที่หลักในการ เขียน และอาน record ไปยัง และออกจากไฟล ตามลําดับ ซึ่งมี code ดังนี้ //Employee.java - Simple record for random-access file import java.io.*; import java.io.RandomAccessFile; import java.lang.String; class Employee { private String firstName; //15 characters (30 bytes) private String lastName; //15 characters (30 bytes) private int year; //4 bytes private double salary; //8 bytes private static final int RECORD_SIZE = 72; //default constructor Employee() { firstName = ""; lastName = ""; year = 0; salary = 0.0D; } //setting up fields Employee(String firstName, String lastName, int year, double salary) { this.firstName = firstName; this.lastName = lastName; this.year = year; this.salary = salary; } //write a record to a file with a given position public void write(RandomAccessFile file, int position) throws IOException { try { //locate a position file.seek((long)(position * RECORD_SIZE)); //write equal-length strings writeString(file, firstName, 15); writeString(file, lastName, 15); //write int and double file.writeInt(year); file.writeDouble(salary); } catch(IOException e) { System.err.println("Error writing file"); e.printStackTrace(); System.exit(1); } }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

232

//reading a record from a file with a given position public void read(RandomAccessFile file, int position) throws IOException { try { //locate position to read file.seek((long)(position * RECORD_SIZE)); //reading strings firstName = readString(file, 15); lastName = readString(file, 15); //reading int and double year = file.readInt(); salary = file.readDouble(); } catch(IOException e) { System.err.println("Error reading file"); e.printStackTrace(); System.exit(1); } } //helper method to write a string with specified length public void writeString(DataOutput out, String s, int len) throws IOException { for(int i = 0; i < len; i++) { if(i < s.length()) out.writeChar(s.charAt(i)); else out.writeChar(0); } } //helper method to read a string public String readString(DataInput in, int len) throws IOException { String s = ""; int i = 0; while(i < len) { char c = in.readChar(); if(c != 0) s += c; i++; } return s; } //number of records in file public int size(RandomAccessFile file) throws IOException{ int size = 0; try { size = (int)file.length() / RECORD_SIZE; } catch(IOException e) { System.err.println("Error reading file."); System.exit(1); } return size; }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

}

Streams I/O

233

//display a record to screen public void show() { System.out.print(firstName + " "); System.out.print(lastName + " "); System.out.print(year + " "); System.out.println(salary); }

method หลัก ๆ ที่อยูใน class Employee คือ write(RandomAccessFile, position) read(RandomAccessFile, position) writeString(DataOutptu, String, length) readString(DataInput, length) size(RandomAccessFile) เนื่องจากวาเราตองรูขนาดของ record ของเราวามีความยาวเทาไร เราจึงจะสามารถทีจ ่ ะเลื่อน logical pointer ของเราไปยังตําแหนงตาง ๆ ที่เราตองการได ดังนัน ้ เราจึงตองกําหนดขนาดของ record ภายใน โปรแกรมของเราเพื่อใหการทํางานสะดวกขึ้น ทั้งนี้การกําหนดขนาดก็ตองขึน ้ อยูกับการเลือกใชวิธีการ เขียนของเราวาใช method ตัวไหนเปนตัวเขียน ถาเราใช writeUTF() เราก็ตองกําหนดขนาดแบบหนึ่ง แตถา เราใช writeChars() เราก็ตองกําหนดขนาดอีกแบบหนึง่ (ดูความแตกตางของการใชจากตาราง) สําหรับโปรแกรมที่เราเขียนขึ้น เรากําหนดใหขนาดของ record เปน 72 byte ก็เพราะวาเราใช writeChar() เปนตัวเขียน ดังนั้น ทั้งชื่อและนามสกุลใช 30 byte สวน year และ salary ใช 4 และ 8 byte ตามลําดับ หนาที่ของ write() คือ การนําขอมูลจาก field ตาง ๆ ของ Employee object เขาสูไฟลในตําแหนงที่ได กําหนดไว ดวยการใช seek() เปนตัวกําหนดตําแหนง file.seek((long)(position * RECORD_SIZE)); เราคูณ position ดวย RECORD_SIZE ก็เพื่อที่จะหาตําแหนงไดถูตอง เนื่องจากวาเรากําหนดให field 2 ตัวแรกมีความยาวเทากับ 15 ตัวอักษร (30 byte) หลังจากนัน ้ เราก็เขียน field ทั้งสองไปยังไฟลดวยการ เรียกใช writeString() ซึ่งทําหนาทีใ่ นการเขียนจํานวน byte ที่ไดกําหนดไว และจะเขียนคา 0 ใน ตําแหนงที่วางอยู ถาความยาวของ field ที่เขียนมีนอยกวา 15 ตัวอักษร //write equal-length strings writeString(file, firstName, 15); writeString(file, lastName, 15); เมื่อเราเขียน field ทั้งสองเสร็จเราก็เขียน อีกสอง filed ที่เหลือดวย writeInt() และ writeDouble() โดย ไมตองทําอะไรพิเศษ //write int and double file.writeInt(year); file.writeDouble(salary); code ของ writeString() ก็ไมยากอะไร เราเขียนขอมูลทีละตัวไปยังไฟลจนกวาจะหมดขอมูลที่อยูใ น string ถาความยาวของ string ที่เราเขียนมีนอ  ยกวาความยาวที่กําหนดไว เราก็เขียนคา 0 ลง ณ ตําแหนง นั้น public void writeString(DataOutput out, String s, int len) throws IOException { for(int i = 0; i < len; i++) { if(i < s.length()) out.writeChar(s.charAt(i)); else

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

}

Streams I/O

234

out.writeChar(0);

}

ในการอาน filed กลับออกมาก็เหมือนกันหลังจากที่ใช seek() หาตําแหนงไดแลว เราก็เรียกใช readString() ในการอานสอง field แรก และใช readInt() กับ readDouble() ในการอานอีกสอง field ที่ เหลือ Code ของ readString() ก็งาย ๆ เราทําการอานทุกตัว แตจะเก็บไวเฉพาะตัวที่ไมใช 0 เพราะ 0 เปนคาที่ เราใชแทนตําแหนงที่วางในการเขียน string เขาสูไฟล public String readString(DataInput in, int len) throws IOException { String s = ""; int i = 0; while(i < len) { char c = in.readChar(); if(c != 0) s += c; i++; } return s; } เราใช readChar() ในการอานขอมูลแตละตัว และเราจะตรวจสอบวาคาทีอ ่ านไดเปน 0 หรือไม ถาไมเราก็ เชื่อมคานี้เขาสู string s พรอมกับเลื่อนไปอานขอมูลตัวตอไป ทําการอานและเชื่อมจนกวาจะหมดขอมูล สําหรับการหาจํานวนของ record ที่มีอยูในไฟลนั้นเราหาไดดว ยการใช ขนาดของไฟลหารดวยขนาดของ record ที่เราไดกําหนดไว public int size(RandomAccessFile file) throws IOException{ int size = 0; try { size = (int)file.length() / RECORD_SIZE; } catch(IOException e) { System.err.println("Error reading file."); System.exit(1); } return size; } เราใช readChar() และ writeChar() ในการเขียนและอานขอมูล ดังนั้นเราตองคํานึงถึงจํานวนของ byte ที่เราตองใชสําหรับ record แตละตัววาถูกตองตามที่ไดกําหนดหรือไม สิ่งที่ตองคํานึงถึงในเรื่องของการ ใช random access file ก็คือ field แตละ field ควรเปน field ที่มีขนาดตายตัว เพราะจะทําใหการคนหา ตําแหนงทําไดอยางถูกตอง ผลลัพธที่เราไดจากการ run คือ Number of records = 4 Record Record Record Record

#1: #2: #3: #4:

John Kawakami 1965 2400.0 Paul Collins 1978 500.0 Stephen Anderson 1985 5000.0 Hendrix McCoy 1972 9500.0

เรามาลองดูตัวอยางการปรับปรุงขอมูล (update) ที่อยูใ นไฟลกัน

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

235

การ update ขอมูลก็คลาย ๆ กับการเขียนขอมูลเขาสูไฟล เราตองหาตําแหนงของ record ที่ตองการ update ใหเจอ ซึ่งเมื่อเจอแลวการเปลี่ยนแปลงขอมูลก็สามารถทําได เราเลือกที่จะเปลีย ่ นแปลง record ของเราทุก field เพื่อเปนการแสดงถึงวิธีการในการ update แตในทางปฏิบัติจริง คงไมมใี ครทําแบบนี้ คําสั่งหลัก ๆ ในการ update คือ f.seek((long)(recNum – 1) * em.recSize()); em.write(f, recNum – 1); record ของเราถูกเก็บในตําแหนงที่นอยกวาที่เปนจริงอยูห  นึ่งคา ดังนั้นการใช seek() เราจึงตองหักออก หนึ่งคา เราไดเขียน method ขึ้นใหมอีกหลายตัวเพื่อชวยใหการกําหนด และ การดึงขอมูลออกจาก record ทําไดโดยไมมีปญหา method ที่เพิ่มขึ้นใน class Employee คือ public void setFirstName(String name) { firstName = name; } public void setLastName(String name) { lastName = name; } public void setSalary(double pay) { salary = pay; } public int recSize() { return RECORD_SIZE; } public void setYear(int y) { year = y; } สําหรับกระบวนการหลัก ๆ ที่เกี่ยวของกับการ update ขอมูลก็ไมมีอะไรมาก หลังจากที่รับขอมูลใหมมา จาก keyboard แลว พรอมกับหาตําแหนงที่ตอ  งการ update เจอเราก็ทําการเขียนขอมูลใหมทับลงที่เดิม … System.out.print("Enter record number: "); buffer = new BufferedReader(new InputStreamReader(System.in)); str = buffer.readLine(); recNum = Integer.parseInt(str); System.out.print("Enter first name: "); emp.setFirstName(buffer.readLine()); System.out.print("Enter last name: "); emp.setLastName(buffer.readLine()); System.out.print("Enter year of birth: "); emp.setYear(Integer.parseInt(buffer.readLine())); System.out.print("Enter salary: "); emp.setSalary(Double.parseDouble(buffer.readLine())); และ code สําหรับการเขียนทับที่เราไดพด ู กอนหนานี้ … f.seek((long)(recNum – 1) * em.recSize()); em.write(f, recNum – 1); ผลลัพธของการ run >java Update temp.dat

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Enter Enter Enter Enter Enter

236

record number: 1 first name: My name last name: Is changing year of birth: 1965 salary: 2500

Record Record Record Record >java Enter Enter Enter Enter Enter

Streams I/O

#1: #2: #3: #4:

My name Is changing 1965 2500.0 Hendrix McCoy 1972 9500.0 John Kawakami 1965 2400.0 John Kowalski 1990 5400.0

Update temp.dat record number: 3 first name: Jennie last name: Saiudom year of birth: 1995 salary: 500

Record Record Record Record

#1: #2: #3: #4:

My name Is changing 1965 2500.0 Hendrix McCoy 1972 9500.0 Jennie Saiudom 1995 500.0 John Kowalski 1990 5400.0

โปรแกรมตัวอยางนี้ update ทุก field ที่มีอยูใน record ดวยการกําหนดขอมูลที่เขามาใหมใหกับ object จาก class Employee เสร็จแลวก็เขียน object ใหมนี้ลงในไฟล ซึ่งการกระทําแบบนี้เราไมสามารถที่จะ update บาง field ที่มีอยูได เราตอง update ทั้งหมด สําหรับการ update เฉพาะ field ที่ตองการนั้น จะ ทิ้งไวใหเปนแบบฝกหัดทายบทตอไป ตัวโปรแกรมทั้งหมด มีดังนี้คือ //Update.java - Updating Random-access file import java.io.RandomAccessFile; import java.io.*; import java.lang.Integer; class Update { public static void main(String[] args) throws IOException { RandomAccessFile f = null; Employee em = new Employee(); if(args.length < 1) { System.err.println("Usage: Update file-name"); System.exit(1); }

}

try { f = new RandomAccessFile(args[0], "rw"); int recNum = getNewData(f, em); //get new data updateData(f, recNum, em); //update record showData(f, args[0]); //display records } catch(IOException e) { System.err.println("Error processing file"); e.printStackTrace(); System.exit(1); }

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

237

//get new data from keyboard private static int getNewData(RandomAccessFile f, Employee emp) throws IOException { BufferedReader buffer = null; InputStreamReader iStream = null; String str = ""; int recNum = 0;

}

try { System.out.print("Enter record number: "); buffer = new BufferedReader( new InputStreamReader(System.in)); str = buffer.readLine(); recNum = Integer.parseInt(str); System.out.print("Enter first name: "); emp.setFirstName(buffer.readLine()); System.out.print("Enter last name: "); emp.setLastName(buffer.readLine()); System.out.print("Enter year of birth: "); emp.setYear(Integer.parseInt(buffer.readLine())); System.out.print("Enter salary: "); emp.setSalary(Double.parseDouble(buffer.readLine())); } catch(IOException e) { System.err.println("Error readin file"); e.printStackTrace(); System.exit(1); } return recNum; //record number

//update record private static void updateData(RandomAccessFile f, int recNum, Employee em) throws IOException { try { //locate record f.seek((long)(recNum – 1) * em.recSize()); //write the whole record em.write(f, recNum – 1); } catch(IOException e) { System.err.println("Error writing file"); e.printStackTrace(); System.exit(1); } finally { if(f != null) f.close(); } } //display all records in this file private static void showData(RandomAccessFile f, String fName) throws IOException { try { f = new RandomAccessFile(fName, "r"); Employee em = new Employee();

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

238

int num = em.size(f); for(int i = 0; i < 4; i++) { em.read(f, i); System.out.print("Record #" + (i+1) + ":"); em.show(); }

}

}

} catch(IOException e) { System.err.println("Error reading file"); e.printStackTrace(); System.exit(1); } finally { if(f != null) f.close(); }

สรุป เราไดแสดงตัวอยางของการทํางานกับ text file และ binary file การอาน การเขียน รวมไปถึง กระบวนการตาง ๆ ที่เกี่ยวของกับไฟล โดยสรุปแลวเราไดพด ู ถึง 9 9 9 9 9 9 9 9 9

การตรวจสอบขอมูลที่เกี่ยวของกับไฟลดวย File และ method ตาง ๆ เชน ifFile() canRead() เปน ตน การใช FileReader FileWriter FileInputStream FileOutputStream การใช DataOutputStream BufferedOutputStream การใช StreamTokenizer และ StringTokenizer การสรางและใชงาน text file การใช delimiter ในการอานขอมูลจาก text file การสรางและใชงาน binary file การสรางและใชงาน Random-access file การ update ขอมูลใน random-access file

แบบฝกหัด 1. จงเขียนโปรแกรมทีท ่ ําหนาทีแ ่ สดงขอมูลเกี่ยวกับไฟลทุกตัวที่มีอยูใน directory นั้น ๆ เชน ถาเจอ ไฟลใหแสดงถึง ขนาด วันทีส ่ ราง ถาเจอ directory ใหแสดงถึงจํานวนไฟลที่มีอยูใ น directory นั้น พรอมกับวันที่ directory นี้ถูกสรางขึ้น 2. จงเขียนโปรแกรมที่ copy ขอมูลจากไฟลหนึง่ ไปยังอีกไฟลหนึ่งผานทาง command-line 3. จงเขียนโปรแกรมทีส ่ รางขอมูลชนิด int ดวยการสุมจํานวนเทากับ 100 ตัว หลังจากนั้นใหนําขอมูล ทั้งหมดไปเก็บไวใน text file โดยกําหนดใหจํานวนของขอมูลตอแถวเทากับ 10 ตัว 4. จงเขียนโปรแกรมที่อานขอมูลจากไฟลที่เขียนขึ้นในขอ 3 เสร็จแลวใหคํานวณหาผลรวมของขอมูลใน แตละแถว หลังจากนั้นใหเขียนขอมูลในแตละแถวรวมทั้งผลรวมที่หาไดลงในไฟลตัวเดิม (ขอมูลใน แตละแถวจะมีจาํ นวนเทากับ 11 ตัวโดยทีต ่ ัวสุดทายในแถวเปนผลรวมของขอมูลในแถวนั้น) 5. จงปรับปรุงโปรแกรมที่เขียนขึ้นในขอ 4 โดยใหมีการคํานวณหาคาเฉลี่ยของขอมูลทุกตัวในแนวตั้ง (column) นําผลลัพธที่ไดพรอมทั้งขอมูลในแตละแถวไปเก็บไวในไฟลตัวใหม 6. จงเขียนโปรแกรมที่อานขอมูลในรูปแบบที่กําหนดใหดานลางนี้ หลังจากนั้นใหแสดงขอมูลที่อานได ไปยังหนาจอ โดยไมตองแสดง delimiter ที่ใช ใหกําหนดจํานวนของขอมูลที่มีอยูในไฟลจาํ นวน เทากับ 10 แถว

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


บทที่ 8 เริ่มตนกับ Java

Streams I/O

239

John Longman+25.0+30.50+48.00 Peter Wang+35.00+50.00+98.00 … … Mike Kawakami+90.00+80.00+85.00 7. จงเขียนโปรแกรมทีส ่ ราง binary file จาก class Student ทีก ่ ําหนดใหนี้ โดยทําการอานขอมูล เบื้องตนมาจาก keyboard ซึ่งมีขอมูลดังนี้ ชื่อตน เปน String จํานวน 15 ตัวอักษร นามสกุล เปน String จํานวน 15 ตัวอักษร เกรด เปน array ที่เก็บ double เชน 85.0 90.5 ทั้งนีจ ้ ํานวนของเกรดที่มีอยูจะมีกต ี่ ัวก็ได เสร็จแลวใหทาํ การอานขอมูลกลับออกมาจากไฟล พรอมทัง้ คํานวณหาเกรดเฉลีย ่ ของขอมูล (นักศึกษา) ทุกตัว เมื่อไดเกรดเฉลี่ยแลวใหแสดงผลออกทางหนาจอ class Student { String firstName; String lastName; double[] grades; } 8. จงเขียนโปรแกรมทีส ่ ราง random-access file จากโครงสรางของ Student ที่มีอยูในขอ 7 โดยให user เปนผูกําหนดตําแหนงของ record ที่ตอ  งการเขียนเอง ใหเขียน method ที่แสดงขอมูลของ record (ที่กําหนดมาจาก keyboard) ไปยังหนาจอ 9. จงปรับปรุงโปรแกรม Update ในบทนีใ้ หมีการ update ไดเฉพาะ field ที่เปน salary เทานั้น 10. จงปรับปรุงโปรแกรมในขอ 6 ดวยการเพิ่ม method ในการคํานวณหาผลรวมของขอมูลในแตละแถว หลังจากนั้นใหนําขอมูลทั้งหมดไปเก็บไวในไฟลตวั ใหม โดยใหผลรวมทีห ่ าไดเปนขอมูลตัวสุดทาย ในแถวนัน ้

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอีสเทอรน


ตารางตาง ๆ

240

เริ่มตนกับ Java

ตารางตาง ๆ ตารางที่ 1 Unicode characters – dec hex char Dec 0 0000 <NUL> 33 1 0001 <SOH> 34 2 0002 <STX> 35 3 0003 <ETX> 36 4 0004 <EOT> 37 5 0005 <ENQ> 38 6 0006 <ACK> 39 7 0007 <BEL> 40 8 0008 <BS> 41 9 0009 <HT> 42 10 000A <LF> 43 11 000B <VT> 44 12 000C <FF> 45 13 000D <CR> 46 14 000E <SO> 47 15 000F <SI> 48 16 0010 <DLE> 49 17 0011 <DC1> 50 18 0012 <DC2> 51 19 0013 <DC3> 52 20 0014 <DC4> 53 21 0015 <NAK> 54 22 0016 <SYN> 55 23 0017 <ETB> 56 24 0018 <CAN> 57 25 0019 <EM> 58 26 001A <SUB> 59 27 001B <ESC> 60 28 001C <FS> 61 29 001D <GS> 62 30 001E <RS> 63 31 001F <US> 64 32 0020 blank 65

128 ตัวแรก hex char 0021 ! 0022 " 0023 # 0024 $ 0025 % 0026 & 0027 ' 0028 ( 0029 ) 002A * 002B + 002C ' 002D 002E . 002F / 0030 0 0031 1 0032 2 0033 3 0034 4 0035 5 0036 6 0037 7 0038 8 0039 9 003A : 003B ; 003C < 003D = 003E > 003F ? 0040 @ 0041 A

dec 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

hex 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F 0060 0061 0062

ตารางที่ 2 Constants ที่ใชบอย ๆ ในโปรแกรม ชื่อ Math.E Math.PI Float/Double.NEGATIVE_INFINITY Float/Double.POSITIVE_INFINITY Float/Double.NaN Byte/Short/Integer/Long/Float/Double.MAXIMUM_VALUE Byte/Short/Integer/Long/Float/Double.MINIMUM_VALUE System.in System.out System.err

char B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _

dec 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128

hex 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F 0080

char c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ <DEL>

a b

ความหมาย คาของ e (natural logarithm) คาของ PI (3.145) infinity ที่เปนลบ infinity ที่เปนบวก ไมใชตัวเลข คาสูงสุด คาต่ําสุด ทางเขาขอมูล (keyboard) ทางออกขอมูล (จอ) ทางออกของ error (จอ)

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัย ฟารอีสเทอรน


ตารางตาง ๆ

241

เริ่มตนกับ Java

ตารางที่ ชนิด byte short int long float double

3 Numeric Types bit คาเบื้องตน 8 0 16 0 32 0 64 0 32 0.0f 64 0.0d

ตารางที่ 4 Escape Sequences Escape Sequence \b \t \n \f \r \" \' \\ \uxxxx \xxx

คาต่ําสุด -128 -32768 -2147483648 -9223372036854775808 1.40129846432481707e-45f 4.94065645841246544e-324

คาสูงสุด 127 32767 2147483647 9223372036854775807 3.40282346638528860e+38f 1.79769313486231570e+308

ความหมาย back space tab LF (ขึ้นบรรทัดใหม) FF (ขึ้นหนาใหม) CR (กลับไปยังจุดเริ่มตน) double quote single quote back slash Unicode จาก \u ตามดวยเลขฐาน 16 สี่ตวั เลขฐานแปด เชน \101

ตารางที่ 5 Format Syntax สําหรับตัวเลข form คา ผลลัพธ 0000 314 0314 ###0 314 314 ##0.0# 3.10 3.1 #,##0 3000 3,000 ##0.00% 3.1415 314.15% \u00A4##0 314 $314

ความหมาย 0 –ใชแทน digit # - ใชแทน digit . - จุดทศนิยม , - ใชแบงกลุมตัวเลข % - คูณตัวเลขดวย 100 เพื่อแสดง % \u00A4 – แสดงสกุลเงินตาม locale ของประเทศ

ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัย ฟารอีสเทอรน


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.