เริ่มตนกับ
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 ของประเทศ
ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัย ฟารอีสเทอรน