1. Trang chủ
  2. » Thể loại khác

Lập trình JAVA hiệu quả

58 164 0
Tài liệu được quét OCR, nội dung có thể không chính xác

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 58
Dung lượng 11,16 MB

Nội dung

Trang 1

LẬP TRÌNH JAVA HIỆU QUA

Tac gia: Joshua Bloch Trình bày: Lê Quốc Anh

30-05-2015

Trang 2

VN-Có nhận xét gì về đoạn code này ?

List<Integer> lst = new ArrayList<Integer>() ;

Trang 3

Có gì khác nhau?

List<Integer> lst = new List<Integer> lst = new

ArrayList<Integer>() ; LinkedList<Integer>() ;

Iterator<Integer> iter = Iterator<Integer> iter =

1st.iterator(); Let., iterator ();

while (iter.hasNext()) { while (iter.hasNext()) {

AL aele TẤN

iter.remove () ; iter remove () ;

Trang 4

So sánh thời gian thực hiện remove ArrayList LinkedList 4 Lst.Size() Lst.Size() Ạ | Ẻ > — ——>

Running time Running time

Trang 7

)

Trang 8

Effective Java

Trang 9

PHAN 1: TAO VA HUY ĐỐI

Trang 10

Quy tắc 1: Dùng hàm gọi đối tượng

» _ Định nghĩa: Là hàm trả lại một đối tượng của lớp

public static Boolean valueOf(boolean b) {return b ? Boolean.TRUE : Boolean.FALSE;

* Loi ich:

— Không cần phải khởi tạo lớp mỗi lần gọi

— Gọi đến cùng một đối tượng (ví dụ Singleton ở phần sau)

— Dé doc (ham cé tén gọi, rút gọn tham số, etc ) Ví dụ:

“Cách bình thường: Map<String, List<String>> m=new HashMap<String, List<String>>();

*Với hàm khởi tạo: Map<String, List<String>> m=HashMap.newlnstance();

* Quy udc:

— lớp chứa hàm kiểu này không nên được khởi tạo trực tiếp nữa, vì đã có hàm khởi tạo va tra

lại đối tượng của lớp rồi Do vậy lớp hoặc constructor của lớp được khai báo private

— _ Nếu đối tượng trả về có tên gọi là Type thì lớp chứa hàm factory sé có tên la Types Ví dụ

public interface book { public void cover(); }

public abstract class Books() { public static Book createBook(){ return new MyBook(); } private class MyBook implements Book{ public void cover(){} } }

Trang 11

Quy tắc 1: Dùng hàm gọi đối tượng

° Điểm hạn chế:

— Lớp chứa các static factory methods không cho phép

kế thừa Ví dụ không thể kế thừa lớp

java.util.Collections (theo quy ước lớp này có giao

diện tên là java.util.Collection không có s) Nguyên nhân là để các lập trình viên nên dùng composition thay vì inheritance mà ta sẽ xem trong Quy tắc 16

— Không có sự khác biệt rõ ràng giữa các hàm static

Trang 12

Quy tắc 2: Dùng builder cho lớp có

nhiều tham số

* _ Xem xét lỚp:

public class NutritionFacts (

private final int servingSize; // (mL) required

private final int servings; // (per container) required

private final int calories; // optional

private final int fat; // (g) optional

private final int sodium; // (mg) optional private final int carbohydrate; // (g) optional

}

NutritionFacts cocaCola = new NutritionFacts(size, serving, calos, fat, sodium, carbo);

* Hạn chế: Nhiều tham số tùy chọn nhưng vẫn phải khai báo hết khi khởi tạo

* Giải pháp 1: Khởi tạo đối tượng và dùng hàm setter

— Vidu public void setFat(int val) { fat = val; }

— _ Không khả thi cho lớp bất biến

* _ Giải pháp 2: Dùng lớp trung gian builder để tùy chọn khai báo tham số

public class NutritionFacts { public static class Builder {

Trang 13

Quy tắc 2: Dùng builder cho lớp có

nhiều tham số

public class NutritionFacts {

public static class Builder {

}

private final int servingSize; // bat budc

private int calories = 0; // tùy chọn, khởi tạo với giá trị mặc định private int fat = 0; // tùy chọn, khởi tạo với giá trị mặc định

public Builder(int servingSize) {this.servingSize = servingSize; } public Builder calories(int val) { calories = val; return this; } public Builder fat(int val) { fat = val; return this; }

Trang 14

Quy tắc 3:Xây dựng lớp Singleton với kiểu Enum

* - Câu hỏi: Singleton khác với lớp bất biến???

*- Định nghĩa: Lớp chỉ được khởi tạo 1 lần duy nhất Ví dụ:

// Singleton with static factory public class Elvis {

private static final Elvis INSTANCE = new Elvis(); private Elvis() { }

public static Elvis getInstance() { return INSTANCE; } public void leaveTheBuilding() { }

Trang 15

Quy tắc 3:Xây dựng lớp Singleton với kiểu Enum

// Singleton with static factory

public class Elvis implements Serializable {

private transient String[] songs= {« a», « b »};

private static final Elvis INSTANCE = new Elvis(); private Elvis() { }

public static Elvis getInstance() { return INSTANCE; }

public void leaveTheBuilding() { }

// readResolve method to preserve singleton property

private Object readResolve() {

// Return the one true Elvis and let the garbage collector // take care of the Elvis impersonator

return INSTANCE;

}

*Deserialization sẽ gọi hàm constructor để tạo ra đối tượng mới ngay cả khi nó được khai báo private

*readResolve() bình thường sẽ trả lại đối tượng mới được tạo mới sau khi deserialized => viết lại

Trang 16

Quy tắc 3:Xây dựng lớp Singleton với kiểu Enum

+ Giải pháp ngắn gọn và an toàn hơn là dùng Enum

public enum Elvis {

INSTANCE;

private transient String[] songs= {« a », « b »};

public void leaveTheBuilding() { }

}

Trang 17

Quy tắc 4: Cấm khởi tạo lớp với

private constructor

*_ Đôi khi ta muốn xây dựng lớp chỉ chứa các

static methods hay static fields

* Giải pháp khai báo lớp kiểu trừu tượng

Abstract không hiệu quả vì lớp con của nó

vẫn có thể được khởi tạo

* Giải pháp triệt để là khai báo lớp với private

Trang 18

Quy tắc 5: Tránh tạo đối tượng thừa

* Vi du: String s = new String("stringette"); — Có đến 2 đối tượng được tạo ra

— Tương đương: String s = "stringette”;

° Giải pháp chung:

— Str dung static factory methods (Quy tac 1) — Sử dụng phương phap Jazy initialization

Trang 19

Quy tắc 6: Loại bỏ các tham chiếu

đến đối tượng không dùng nữa

° Xét vi du sau:

public class Stack {

private Object[] elements; private int size = 0;

private static final int DEFAULT_INITIAL_CAPACITY = 16;

public Stack() {

elements = new Object[DEFAULT_INITIAL_CAPACITY];

}

public Object pop() {

if (size == 0) throw new EmptyStackException();

Trang 20

Quy tắc 6: Loại bỏ các tham chiếu

đến đối tượng không dùng nữa

° Xét ví dụ sau:

public Object pop() {

if (size == 0) throw new EmptyStackException();

Object result = elements|[ size];

elements[size] = null; // Eliminate obsolete reference return result;

}

* Giải pháp: chú ý giải pháp bộ nhớ khi xây

Trang 21

Quy tắc 7: Tránh sử dụng finalizers

° Định nghĩa: Garbage collector (GC) trong Java phụ trách giải phóng các đối tượng không còn có thể được sử dụng (unreacheable) Trước khi giải phóng đối tượng thì hàm finalize() của đối tượng đó sẽ được gọi

»- Sử dụng finalizers nguy hiểm? Vì sao?

— Không dự đoán được kết quả: thời gian từ lúc một đối tượng thành unreachable cho tới lúc được GC xử lý là không xác định — Ngay cả ép chạy GC bằng lệnh System.gc vì nó cũng không

đảm bảo để finalize() của đối tượng được thực thi tức thời

— Sử dụng finalize() làm tăng thời gian thực hiện lên 430 lần (cần

Trang 22

Quy tac 7: Tránh sử dụng

finalizers

* Giải pháp

— Thay thế bằng try finally

— Hoặc gọi lệnh System.runFinalizersOnexit hoặc

Runtime.runFinalizersOnExit Tuy nhiên cả 2 hàm

này không còn được sử dụng (deprecated) bởi lý

do nó có thể được gọi ngay cả với đối tượng reacheable => gây ra các hành vi bất thường

Trang 23

Quy tắc 7: Tránh sử dụng

finalizers

*_ Giải pháp

E Nếu buộc phải sử dụng, phải đảm bảo finalize() luôn được gọi

cả ở lớp cha (superclass) và lớp con (subclass) Ví dụ

@Override protected void finalize() throws Throwable { try{

// Finalize subclass state } finally {

super finalize(); } }

— Hoặc sử dụng phương pháp finalizer guardian để đảm bảo finalize() luôn được gọi Ví dụ:

public class Foo {

Foo object private final Object finalizerGuardian = new

Object() {

@Override protected void finalize() throws Throwable { }

Trang 24

PHẦN 2: PHƯƠNG THỨC

Trang 25

Quy tắc 8: Điều kiện khi viết lại hàm

equals()

° Trước hết trả lời câu hỏi liệu việc viết lại hàm equals có cần thiết không???

Co hai loai lop (value classes vs activity classes) Doi voi mot activity class nhu lop Thread thi khong can phai viet lai

Khong can quan tam lieu ham equals hien co co hop ly khong Vi du nhu viet lai ham equals cho lop Random de bat buoc 2 the hien cua lop Random duoc cho la bang nhau neu va chi neu

chung san xuat mot chuoi cac gia tri giong nhau Cai nay phai xem lai nhu cau co can thiet ko

Cac lop cua Set: HashSet, TreeSet, hay cac lop cua List:

ArrayList, LinkedList, da viet de ham equals thich hop cho chung roi thi cung ko nen viet lai

Trang 26

Quy tắc 8: Điều kiện khi viết lại hàm

equals()

+ Nếu cần viết lại hàm equals thì phải tuân thủ 5 quy định sau:

1 Phan chieu: No phai bang no, x.equals(x) luon dung

2 Doi xung: x.equals(y) dung khi va chi khi y.equals(x) cung dung 3 Bac cau: Neu x.equals(y) va y.equals(z) dung thi x.equals(z) cung

dung

4 Vung chac: Neu x va y la cac gia tri khong null thi x.equals(y) se phai luon tra lai gia tri nhu nhau moi khi duoc goi den cho du cac gia tri khong thuoc equals cua lop x va y co the bi thay doi Loi khuyen la khong neu dung cac resources khong tin cay de xay dung ham equals

Trang 27

Quy tắc 8: Điều kiện khi viết lại hàm

equals()

* - Cách xây dựng hàm equals hiệu quả:

— Dau tien kiem tra bang toan tu == xem lieu chung co reference

den cung doi tuong khong (vd: if (o == this) return true;)

— Kiem tra xem chung co cung kieu khong bang toan tu

instanceof (vd: if (!(o instanceof PhoneNumber)) return false;) — Ep kieu de chung ve cung kieu (vd: PhoneNumber pn =

(PhoneNumber)o;)

— So sanh tung doi so (argument) xem chung co tuong ung voi

nhau khong (vd: return pn.lineNumber == lineNumber &&

pn.prefix == prefix && pn.areaCode == areaCode;)

— Sau khi viet xong ham equals, kiem tra lai xem no co tuan thu 5 quy dinh khong

Trang 28

Quy tắc 9: Luôn viết lại hashCode()

sau khi thay đổi hàm equals()

1 Trong một phiên làm việc nếu hàm hashCode được gọi lại nhiều lần thì kết quả trả lại đều phải như nhau Tuy nhién, néu đó là 2 phiên làm việc khác nhau thì có thể cho kết quả hashCode khác nhau

2 Nếu hai đối tượng x, y được tính là bằng nhau theo hàm

X equals(y)==true, thì x hashCode() == y.hashCode()

3 Ngược lại, nếu x equals(y) == false, thi ham hashCode() cUa x va y không nhất thiễt phải khác nhau

Trang 29

Quy tắc 9: Luôn viết lại hashCode()

sau khi thay đổi hàm equals()

Điều 2 « đối tượng bằng nhau theo equals thì hashCode phải bằng nhau» hay bị vi phạm khi ta viết lại hàm equals Ví dụ:

@Override public boolean equals(Object o) {

if (o == this) return true;

if (!(o instanceof PhoneNumber)) return false;

PhoneNumber pn = (PhoneNumber)o;

return pn.lineNumber ==lineNumber && pn.prefix

== prefix && pn.areaCode == areaCode;

}

Map<PhoneNumber, String> m =new

HashMap<PhoneNumber, String>(); m.put(new PhoneNumber(707, 867, 5309), "Jenny");

Chúng ta hi vọng lời gọi m.get(new PhoneNumber(707 , 867,

Trang 30

Quy tắc 9: Luôn viết lại hashCode()

sau khi thay đổi hàm equals()

* Cach giai quyet don gian nhat la viet lai ham hashCode nhu sau:

@Override public int hashCode() {

return 42;

}

Trang 31

Quy tắc 9: Luôn viết lại hashCode()

sau khi thay đổi hàm equals()

Cach giai quyet don gian nhat la viet lai ham hashCode nhu

sau:

@Override public int hashCode() { return 42; }

Cach lam nhu tren co on thoa khong?

Khong, vi nhu vay tat ca cac doi tuong se co cung gia tri

hashCode Khi do bang bam se phai su dung danh sach lien

ket (linkedList) de tim kiem doi tuong va do do lam giam hieu

suat tim kiem

Giai phap hay nhat la xay dung hashCode sao cho hai doi tuong khong bang nhau se ko co chung gia tri hashCode =>

Trang 32

Quy tắc 9: Luôn viết lại hashCode()

sau khi thay đổi hàm equals()

* Nguyen tac xay dung an toan ham hashCode:

— la chi su dung cac gia tri dung trong ham equals

— Can doi giua running time tong the he thong so voi running time cua ham hashCode Loi khuyen la khong nen ngai su dung tỉnh toan phục tap hashCode

— Neu viec tinh toan hashCode phuc tap, khong nen tinh lai no nhieu lan cho mot doi tuong, cung nhu chi tinh toan no khi doi tuong duoc tao ra Vi du:

private volatile int hashCode; // (Xem quy tac 71)

@Override public int hashCode() {

int result = hashCode;

if (result == 0) { result = 17; result = 31 * result + areaCode;

result = 31 * result + prefix; result = 31 * result + lineNumber;

}

Trang 33

Quy tắc 10: Nên viết lại toString()

* ham toString nen tra lai toan bo thong tin ve doi tuong * viet tai lieu ro rang ve dinh dang du lieu tra ve cua

toString- cung cap ham truy cap den tat ca cac thong tin

tra ve boi toString

— LTV khong can phai xu ly chuoi String ket xuat thong tin nao do — Kho kiem soat khi dinh dang du lieu tra ve cua toString thay

doi

— Vi du, binh thuong lop PhoneNumber.toString se tra lai

"PhoneNumber@14845" tuong ung "ten lop@gia tri hashCode viet duoi dang unsigned hexadecimal" Chung ta co the viet lai ham toString ro rang hon de tra lai gia tri vi du "(0084) 043 -

Trang 34

Quy tắc 11: Cẩn thận khi viết lại clone

* Định nghĩa: tao ra mot doi tuong moi voi tat ca thuoc tinh giong y chang mot doi tuong khac ma khong can goi den ham khoi tao

* Nguyen tac viet ham clone:

— x.clone() != x: Day phai hoan toan la 2 doi tuong doc lap nhau Chu y: cac doi tuong mutables co cau truc "deep structure" can duoc sao chep theo phuong

phap "deep copy"

— x.clone().getClass() == x.getClass(): chu y super.clone phai duoc khai bao trong ham clone

Trang 35

Quy tắc 12: Thực thi Comparable

* Dinh nghia: Lop a thuc thi Comparable va viet lai ham compareTo() Khi do Array.sort(dsa) se sap xep danh sach cac doi tuong cua lop a theo tieu chi cua ham

compareTo()

* Nguyen tac xay dung ham compareTo()

— Doi xung: sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) dung cho moi x, y — Bac cau: (x.compareTo(y)>0 && y.compareTo(z)>0) keo theo x.compareTo(z)>0 — Vung chac: Neu (x.compareTo(y)==0) thi (x.compareTo(z) == y.compareTo(z))

Trang 37

Quy tắc 13: Hạn chế truy cập lớp và

các thành viên bên trong lớp

Mot modul duoc cho la thiet ke tot neu no ẩn duoc cac du lieu va cac ham xu ly du lieu cua no khoi su truy cap boi cac module khac (ie., tinh dong goi) => de phat trien song song, cai tien doc lap, de

phat hien loi, de bao tri,

Uu tien neu co the khai bao lop hoac giao dien la package-private

class/interface Boi vi neu khai bao public, ban bat buoc phai bao

tri tinh tuong thich cua no mai mai do no co the duoc su dung o dau do ben ngoai package

ngay ca cach viet hang so cho du lieu mang (ie public static final array) cung khong dam bao noi dung khong bi sua doi: Nen dung ham tra ve doi tuong Vi du dung:

private static final Thing[] PRIVATE_VALUES = { }; public static final List<Thing> VALUES =

Trang 38

Quy tắc 14: Dùng øccessor methods

để truy cập các biến bên trong lớp

* Tat ca cac truong (fields) cua public classes

phai duoc truy cap thong qua ham tuong ung *- Nhu giai thich trong quy tac 13, de no dam

bao tỉnh bao dong

Trang 39

Quy tắc 15: immutable vs mutable

Định nghĩa?

* Bat dau qua vi du sau

Trang 40

Quy tắc 15: Nhận xét gì về đoạn code

này?

String string = "";

for (int i= 0; i < times; itt) {

string/+ string: concati("stsa)y

}

times

Running time

Ngày đăng: 12/06/2017, 19:54

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w