Giáo trình Lập trình truyền thông (Phần 4)

pdf 10 trang phuongnguyen 2900
Bạn đang xem tài liệu "Giáo trình Lập trình truyền thông (Phần 4)", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pdfgiao_trinh_lap_trinh_truyen_thong_phan_4.pdf

Nội dung text: Giáo trình Lập trình truyền thông (Phần 4)

  1. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông 1.3.9. Một số vấn đề khác 1.3.9.1. Đọc đối số của chương trình Khi thực thi chương trình ta có thể nhập vào các đối số từ dòng lệnh theo cú pháp sau: java ClassName arg1 arg2 arg3 argn Các đối số cách nhau khoảng trắng. Để đón nhận các đối số này, phương thức main bắt buộc phải khai báo một tham số kiểu mảng các chuỗi public static void main(String args[]) { } Các đối sối số lần lượt được đặt vào các phần tử của mảng này. Số lượng đối số có thể xác định được bằng cách truy xuất thuộc tính args.length của mảng. Ví dụ Lưu chương trình sau vào tập tin PrintArgs.java public class PrintArgs { public static void main (String args[]) { for (int i = 0; i < args.length; i++) { System.out.println(args[i]); } } } Biên dịch và thực thi chương trình được kết quả sau: Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 30
  2. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông 1.3.9.2. Đổi chuỗi thành số Lưu chương trình sau vào tập tin StringToNumber.java public class StringToNumber{ public static void main (String args[]) { int i = Integer.valueOf( args[0]).intValue(); long l = Long.valueOf( args[1]).longValue(); float f = Float.valueOf( args[2]).floatValue(); System.out.println("Integer number = "+i ); System.out.println("Long number = "+l ); System.out.println("Float number = "+f ); } } Biên dịch và thực thi chương trình được kết quả sau: 1.4. Ngoại lệ (EXCEPTION) Trong chương trình, có một số các "thao tác không chắc chắn", ví dụ như các thao tác vào/ra: đĩa mềm chưa sẵn sàng, máy in có lỗi, nối kết mạng không thực hiện được . . . sẽ dẫn đến lỗi thực thi chương trình. Java hạn chế các lỗi sinh ra từ "thao tác không chắc chắn" bằng cơ chế Ngoại lệ (Exception). Ngoại lệ tức là một sự kiện xảy ra ngoài dự tính của chương trình nếu không xử lý sẽ làm cho chương trình chuyển sang trạng thái không còn kiểm soát được. Ví dụ điều gì sẽ xảy ra nếu chương trình truy xuất đến phần tử thứ 11 của một mảng 10 phần tử ? Một số ngôn ngữ như C, C++ sẽ không báo lỗi gì cả, chương trình vẫn tiếp tục vận hành nhưng kết quả thì không thể xác định được. Để hạn chế những lỗi như thế, Java bắt buộc các lệnh có thể dẫn đến các ngoại lệ phải có các đoạn mã xử lý phòng hờ khi ngoại lệ xảy ra theo cú pháp sau: Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 31
  3. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông try { Các thao tác vào ra có thể sinh ra các ngoại lệ. } catch (KiểuNgoạiLệ_01 biến) { ứng xử khi ngoại lệ KiểuNgoaiLệ_01 sinh ra } catch (KiểuNgoạiLệ_02 biến) { ứng xử khi ngoại lệ KiểuNgoaiLệ_02 sinh ra }finally { Công việc luôn luôn được thực hiện } Trong cơ chế này, các lệnh có thể tạo ra ngoại lệ sẽ được đưa vào trong khối bao bọc bởi từ khóa try {}. Tiếp theo đó là một loạt các khối catch{}. Một lệnh có thể sinh ra một hoặc nhiều loại ngoại lệ. Ứng với một loại ngoại lệ sẽ có một khối catch{} để xử lý cho loại ngoại lệ đó. Tham số của catch chỉ ra loại ngoại lệ mà nó có trách nhiệm xử lý. Khi thực thi chương trình, nếu một lệnh nào đó nằm trong khối try{} tạo ra ngoại lệ, điều khiển sẽ được chuyển sang các lệnh nằm trong các khối catch{} tương ứng với loại ngoại lệ đó. Các lệnh phía sau lệnh tạo ra ngoại lệ trong khối try{} sẽ bị bỏ qua. Các lệnh nằm trong khối finally{} thì luôn luôn được thực hiện cho dù có xảy ra ngoại lệ hay là không. Khối lệnh finally{} là tùy chọn có thể không cần. Ngoại lệ có loại bắt buộc phải xử lý, tức phải có try{}, có catch{} khi sử dụng lệnh đó. Ví dụ như lệnh đọc từ bàn phím. Trình biên dịch của java sẽ báo lỗi nếu chúng ta không xử lý chúng. Ngược lại, có loại ngoại lệ không bắt buộc phải xử lý, ví dụ như truy xuất đến phần tử bên ngoài chỉ số mảng. Tra cứu tài liệu đặc tả các API của java để biết được các ngoại lệ tạo ra từ một phương thức. Ví dụ: Lưu chương trình sau vào tập tin ExceptionDemo.java : public class ExceptionDemo { public static void main(String[] args) { try { System.out.println("Hello " + args[0]); } catch (ArrayIndexOutOfBoundsException e){ System.out.println("Hello Whoever you are."); } finally { System.out.println("How are you?"); } } } Biên dịch và thực thi có kết quả như sau: Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 32
  4. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông Trong chương trình trên chúng ta dự định sẽ chào người được đưa vào từ đối số thứ nhất của chương tình (được chứa trong phần tử args[0]). Tuy nhiên nếu người dùng thực thi chương trình quên đưa vào đối số, tức phần tử args[0] không tồn tại. Ngoại lệ báo hiệu truy xuất đến phần tử nằm ngoài mảng (ArrayIndexOutOfBoundsException) được quẳng ra (throw). Khi đó đoạn mã lệnh trong khối catch có tham số là loại ngoại lệ ArrayIndexOutOfBoundsException sẽ đưọc thực hiện. 1.5. Một số vấn đề liên quan đến lớp trong Java 1.5.1. Định nghĩa lớp mới Ngoài các lớp được định nghĩa sẵn trong thư viện chuẩn của java, các lập trình viên có thể định nghĩa thêm các lớp của mình theo cú pháp sau: class ClassName { // Danh sách các thuộc tính thuộc lớp DataType01 attribute1, attribute2, . .; DataType02 attribute3, attribute4, . .; // Danh sách các phương thức thuộc lớp ClassName([DataType parameter, DataType parameter]) { // Constructor } void method01() { . . . } DataType method02( . . .) { return xx; } } ClassName là tên lớp mới đang được định nghĩa. Tạo đối tượng tên obj thuộc lớp ClassName. ClassName obj = new ClassName(); Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 33
  5. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông Ví dụ: Định nghĩa một lớp có: • Tên là Person • Hai thuộc tính là name và address • Phương thức khởi tạo có hai tham số để gán giá trị khởi động cho hai thuộc tính. • Phương thức void display() cho biết người đó tên là gì, địa chỉ ở đâu. • Phương thức main() tạo ra một đối tượng tên là tom thuộc lớp Person Lưu chương trình sau vào tập tin Person.java public class Person{ String name; //Thuộc tính String address; //Thuộc tính Person(String n, String address) { // Phương thức khởi tạo name = n; this.address = address; } void display(){ // Hiển thị tên và địa chỉ System.out.print(name + " is at "+ address); } public static void main(String args[]){ Person tom = new Person("Tom","Disney Land"); // Tạo đối tượng tom.display(); // Gọi phương thức của đối tượng } } Biên dịch và thực thi ta được kết quả: 1.5.2. Phạm vi nhìn thấy của một lớp Một lớp được định nghĩa và cài đặt bên trong một tập tin. Một tập tin có thể chứa một hoặc nhiều lớp. Trong một tập tin, chỉ có một lớp được khai báo là public (phía trước từ khóa class), các lớp còn lại phải là private (mặc nhiên). Một lớp được khai báo là public sẽ được nhìn thấy bởi các lớp khác ở cùng tập tin hay khác tập tin với nó. Ngược lại các lớp private chỉ được nhìn thấy bởi các lớp nằm cùng tập tin với nó mà thôi. Ví dụ: Trong ví dụ này, chúng ta tách phương thức main ra khỏi lớp Person và đưa nó vào lớp mới MultiClass. Lưu hai lớp này vào trong cùng một tập tin tên là MultiClass.java, với lớp MultiClass được khai báo là public, lớp Person khai báo private. Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 34
  6. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông // Lớp có phạm vi public có thể tham khảo từ bên ngoài tập tin public class MultiClass { public static void main(String args[]){ Person tom = new Person("Tom","Disney Land"); tom.display(); } } // Lớp có phạm vi private chỉ có thể tham khảo bởi các lớp nằm cùng tập tin class Person{ String name; String address; Person(String n, String address) { name = n; this.address = address; } void display(){ System.out.println(name + " is at "+ address); } } Biên dịch và thực thi ta được kết quả: 1.5.3. Tính thừa kế • Một lớp chỉ có thể có một lớp cha (thừa kế đơn). • Lớp cha được tham khảo từ lớp con bởi từ khóa super. • Dùng từ khóa extends để khai báo thừa kế. Cú pháp: class A extends B { // Khai báo A thừa kế từ B } Ví dụ: Định nghĩa lớp Client có các đặc điểm sau: • Thừa kế từ lớp Person. • Có thêm thuộc tính: telephone và buy (lượng hàng mua). • Có phương thức khởi tạo. • Định nghĩa lại phương thức void display() của lớp cha. Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 35
  7. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông Lưu chương trình sau vào tập tin Client.java public class Client extends Person{ int telephone; long buy; public Client(String n, String a, int t, long b) { super(n,a); telephone=t; buy=b; } public void display() { super.display(); System.out.println( ", Number of telephone:"+ telephone + ", buy: "+ buy ); } public static void main(String args[]){ Client tom = new Client("Tom","Disney Land",123456,1000); tom.display(); } } Biên dịch và thực thi ta được kết quả: 1.6. Vào / Ra với Stream Stream là một dòng liên tục, có thứ tự các bytes dữ liệu chảy giữa chương trình và các thiết bị ngoại vi. Nó là khái niệm trừu tượng giúp giảm bớt các thao tác vào ra phức tạp đối với người lập trình. Nó cho phép nối kết nhiều loại thiết bị ngoại vi khác nhau với chương trình. Nếu dòng dữ liệu trong Stream có hướng chảy từ thiết bị ngoại vi vào chương trình thì ta nói đây là Stream nhập (Input Stream), ngược lại là Stream xuất (Output Stream). Đối với Java, các thiết bị chỉ nhập, như bàn phím, sẽ có các Stream nhập nối với nó, các thiết bị chỉ xuất, như màn hình, sẽ có các stream xuất nối với nó , các thiết bị vừa xuất, vừa nhập, như đĩa từ, thì có cả stream nhập và xuất nối với nó. Để giao tiếp với các thiết bị ngoại vi, chương trình trước tiên phải lấy được các stream nhập / xuất gắn với thiết bị ngoại vi này. Sau đó, chương trình có thể gởi dữ liệu ra ngoại vi bằng thao tác ghi vào Stream xuất của ngoại vi. Ngược lại, chương trình có thể nhận dữ liệu từ ngoại vi bằng thao tác đọc stream nhập của ngoại vi đó. Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 36
  8. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông Như vậy, chương trình chỉ làm việc trên các stream nhập và stream xuất, mà không quan tâm đến đặc điểm riêng biệt của thiết bị ngoại vi nối với Stream. Điều này giúp chương trình giao tiếp với hệ thống mạng cũng dễ dàng như giao tiếp với màn hình, bàn phím hay đĩa từ. Một điểm khác cần lưu ý là stream bao gồm những bytes rời rạc. Những bytes này mô tả những dạng dữ liệu khác nhau. Ví dụ một số integer khi viết vào stream sẽ chuyển thành 4 bytes. Vì thế cần phải có các thao tác chuyển đổi dữ liệu nhận và gởi giữa chương trình và stream. Java hỗ trợ hai các lớp stream cơ bản trong gói java.io là: • java.io.InputStream: Stream nhập • java.io.OutputStream: Stream xuất Ngoài ra còn có các lớp Stream thừa kế từ hai lớp trên nhằm mục đích cung cấp các tiện ích cho các loại thiết bị vào ra chuyên biệt như: FileInputStream, FileOutputStream, PipedInputStream, PipedOutputStream, . . . 1.6.1. Lớp java.io.InputStream Là loại stream cho phép chương trình nhận dữ liệu từ ngoại vi. Có các phương thức cơ bản sau: int read() throws IOException : Đọc 1 byte từ Stream • Return 0-255 : Mã ASCII của byte nhận được từ ngoại vi • -1 : Stream đã kết thúc, không còn dữ liệu. Đối với Java, System.in là một InputStream nối kết với bàn phím được tạo sẵn bởi hệ thống. Chương trình có thể dùng InputStream này để nhận các ký tự nhập từ bàn phím. Ví dụ: Hãy lưu chương trình sau vào tập tin InStream1.java import java.io.*; public class InStream1 { public static void main(String args[]) { InputStream is = System.in; // KeyBoard = System.in while (true) { try { int ch = is.read(); if (ch ==-1 || ch =='q') break; System.out.print((char)ch); } catch (IOException ie) { System.out.print("Error: "+ie); } } } } Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 37
  9. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông Biên dịch và thực thi ta được kết quả sau: Ví dụ trên chờ nhận các ký tự được nhập từ bàn phím. int read(byte b[]) throws IOException: Đọc tất cả các byte hiện có trong Stream vào mảng b. • Return 0-255: Số lượng byte đọc được. • -1 : Stream đã kết thúc, không còn dữ liệu. int read(byte b[], int offset, int len) Đọc len byte từ Stream hiện tại, lưu vào trong mảng b bắt đầu từ vị trí offset • Return: số lượng byte đọc được. • -1 : Stream đã kết thúc. Các phương thức trên khi thực thi sẽ bị nghẽn (block) cho đến khi có dữ liệu hoặc kết trúc Stream hay một ngoại lệ xuất hiện. int available() Trả về số lượng byte hiện có trong Stream mà không làm nghẽn chương trình. Ví dụ: Lưu chương trình sau vào tập tin có tên InStream2.java import java.io.*; public class InStream2 { public static void main(String args[]) { InputStream is = System.in; // KeyBoard = System.in while (true) { try { int num = is.available(); if (num > 0){ byte[] b = new byte[num]; int result = is.read(b); if (result == -1) break; String s = new String(b); System.out.print(s); } else { Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 38
  10. Khoa Công Nghệ Thông Tin - Đại Học Cần Thơ - Giáo Trình Lập Trình Truyền Thông System.out.print('.'); } } catch (IOException ie) { System.out.print("Error: "+ie); } } } } Biên dịch và thực thi ta được kết quả sau: Điểm khác biệt trong ví dụ này là các ký tự ta nhập từ bàn phím sẽ không hiển thị tức thì trên màn hình. Chúng chỉ hiển thị sau khi chúng ta nhấn phím Enter. 1.6.2. Lớp java.io.OutputStream Là loại stream cho phép chương trình xuất dữ liệu ra ngoại vi. Có các phương thức cơ bản sau: void write(int b) throws IOException • Viết byte b vào Stream hiện tại, • Return : void void write (byte[] b) throws IOException • Viết tất cả các phần tử của mảng b vào Stream hiện tại • Return : void void write (byte[] b, int offset, int len) throws IOException: • Viết len phần tử trong mảng b vào Stream hiện tại, bắt đầu từ phần tử có chỉ số là offset của mảng. • Return : void Đối với Java, System.out là một OutputStream nối kết với màn hình được tạo sẵn bởi hệ thống. Chương trình có thể dùng OutputStream này để gởi các ký tự ra màn hình. Biên Soạn: Ngô Bá Hùng - Nguyễn Công Huy 39