You are on page 1of 11

Giӟi thiӋu

Khung công tác cӫa các sưu tұp Java (Java Collections Framework) là rӝng lӟn. Trong hưӟng
dүn Giӟi thiӋu vӅ lұp trình Java, tôi đã nói vӅ lӟp ArrayList, nhưng đó là chӍ bàn sơ qua trên bӅ
mһt. Có rҩt nhiӅu lӟp và giao diӋn trong khung công tác. Tҥi đây, chúng ta sӁ trình bày nhiӅu
hơn, dù không phҧi là tҩt cҧ vӅ chúng.

Các giao diӋn và các lӟp sưu tұp

Khung công tác cӫa các sưu tұp Java dӵa trên triӇn khai thӵc hiӋn cө thӇ mӝt sӕ giao diӋn đӏnh
nghĩa các kiӇu sưu tұp (collection):

KÊ Giao diӋn List đӏnh nghĩa mӝt sưu tұp các phҫn tӱ Object có thӇ dүn hưӟng.
KÊ Giao diӋn ´et đӏnh nghĩa mӝt sưu tұp không có các phҫn tӱ trùng lһp.
KÊ Giao diӋn Ëap đӏnh nghĩa mӝt sưu tұp các cһp khóa - giá trӏ.

Chúng ta sӁ nói vӅ mӝt vài triӇn khai thӵc hiӋn cө thӇ trong hưӟng dүn này. Đây không phҧi là
mӝt danh sách đҫy đӫ, nhưng nhiӅu khҧ năng bҥn thưӡng xuyên thҩy nhӳng thӭ sau đây trong
các dӵ án phát triӇn bҵng ngôn ngӳ Java:

c   
   
 

List ArrayList, Vector

Set Hash´et, Tree´et

Map HashËap

Tҩt cҧ các giao diӋn trong khung công tác, trӯ Ëap là các giao diӋn con cӫa giao diӋn
Collection, trong đó đӏnh nghĩa cҩu trúc chung nhҩt cӫa mӝt sưu tұp. Mӛi sưu tұp gӗm V 
 V. Vӟi vai trò là trình thӵc hiӋn các giao diӋn con cӫa Collection, tҩt cҧ kiӇu sưu tұp chia
sҿ chung (theo trӵc giác) mӝt sӕ hành vi:

KÊ Các phương thӭc đӇ mô tҧ kích thưӟc cӫa sưu tұp (như size() và isEmpty()).
KÊ Các phương thӭc đӇ mô tҧ nӝi dung cӫa sưu tұp (như contains() và containsAll()).
KÊ Các phương thӭc đӇ hӛ trӧ thao tác vӅ nӝi dung cӫa sưu tұp (như add(), remove() và
clear()).
KÊ Các phương thӭc đӇ cho phép bҥn chuyӇn đәi mӝt sưu tұp thành mӝt mҧng (như
toArray()).
KÊ Mӝt phương thӭc đӇ cho phép bҥn nhұn đưӧc mӝt trình vòng lһp (iterator) trên mҧng các
phҫn tӱ (iterator()).

Chúng ta sӁ nói vӅ mӝt sӕ phương thӭc trên trong phҫn này. Đӗng thӡi chúng ta sӁ thҧo luұn

V  V  (iterator) là gì và cách sӱ dөng nó như thӃ nào.
Lưu ý rҵng các Ëap là đһc biӋt. Thұt sӵ chúng hoàn toàn không là mӝt sưu tұp. Tuy nhiên, chúng
có hành vi rҩt giӕng các sưu tұp, vì vұy chúng ta cũng nói vӅ chúng trong phҫn này.

VӅ đҫu trang

Các triӇn khai thӵc hiӋn Danh sách (List)

Các phiên bҧn cũ hơn cӫa JDK chӭa mӝt lӟp đưӧc gӑi là Vector. Nó vүn còn có trong các phiên
bҧn mӟi hơn, nhưng bҥn chӍ nên sӱ dөng nó khi bҥn cҫn có mӝt sưu tұp ¢ V   -- đó là,
mӝt trong nhӳng yӃu tӕ là an toàn phân luӗng. (Nói vӅ phân luӗng đã vưӧt ra ngoài phҥm vi cӫa
bài viӃt này, chúng ta sӁ thҧo luұn ngҳn gӑn vӅ khái niӋm ҩy trong phҫn Tóm tҳt). Trong các
trưӡng hӧp khác, bҥn nên sӱ dөng lӟp ArrayList. Bҥn vүn có thӇ sӱ dөng Vector, nhưng nó áp
đһt mӝt sӕ chi phí thêm mà bҥn thưӡng không cҫn.

Mӝt ArrayList là cái như tên cӫa nó gӧi ý: danh sách các phҫn tӱ theo thӭ tӵ. Chúng ta đã thҩy
làm thӃ nào đӇ tҥo ra mӝt danh sách và làm thӃ nào đӇ thêm các phҫn tӱ vào nó, trong bài hưӟng
dүn giӟi thiӋu trưӟc. Khi chúng ta tҥo ra mӝt lӟp Wallet lӗng trong trong hưӟng dүn này, chúng
ta đã tích hӧp vào đó mӝt ArrayList đӇ giӳ các hoá đơn thanh toán cӫa Adult:

protected class Wallet {


protected ArrayList bills = new ArrayList();

protected void addBill(int aBill) {


bills.add(new Integer(aBill));
}

protected int getËoneyTotal() {


int total = 0;
for (Iterator i = bills.iterator(); i.hasNext(); ) {
Integer wrappedBill = (Integer) i.next();
int bill = wrappedBill.intValue();
total += bill;
}
return total;
}
}

Phương thӭc getËoneyTotal() sӱ dөng mӝt 


V  V  (iterator) đӇ duyӋt qua danh sách
các hoá đơn thanh toán và tính tәng giá trӏ cӫa chúng. Mӝt Iterator tương tӵ như mӝt
Enumeration trong các phiên bҧn cũ hơn cӫa ngôn ngӳ Java. Khi bҥn nhұn đưӧc mӝt trình vòng
lһp trên sưu tұp (bҵng cách gӑi iterator()), trình vòng lһp cho phép bҥn =(traverse)
toàn bӝ sưu tұp bҵng cách sӱ dөng mӝt sӕ phương thӭc quan trӑng, đưӧc minh hӑa trong mã lӋnh
ӣ trên:

KÊ hasNext() cho bҥn biӃt còn có mӝt phҫn tӱ tiӃp theo khác trong sưu tұp không.
KÊ next() cho bҥn phҫn tӱ tiӃp theo đó.
Như chúng ta đã thҧo luұn ӣ trên, bҥn phҧi ép kiӇu đúng khi bҥn trích ra các phҫn tӱ tӯ sưu tұp
khi sӱ dөng next().

Tuy nhiên, Iterator còn cho chúng ta mӝt sӕ khҧ năng bә sung thêm. Chúng ta có thӇ loҥi bӓ
các phҫn tӱ khӓi lӟp ArrayList bҵng cách gӑi remove() (hay removeAll(), hay clear()),
nhưng chúng ta cũng có thӇ sӱ dөng Iterator đӇ làm điӅu đó. Hãy thêm mӝt phương thӭc rҩt
đơn giҧn đưӧc gӑi là spendËoney() tӟi Adult:

public void spendËoney(int aBill) {


this.wallet.removeBill(aBill);
}

Phương thӭc này gӑi removeBill() trên Wallet:

protected void removeBill(int aBill) {


Iterator iterator = bills.iterator();
while (iterator.hasNext()) {
Integer bill = (Integer) iterator.next();
if (bill.intValue() == aBill)
iterator.remove();
}
}

Chúng ta nhұn đưӧc mӝt Iterator trên các hoá đơn thanh toán ArrayList, và duyӋt qua
danh sách đӇ tìm mӝt kӃt quҧ khӟp vӟi giá trӏ hóa đơn đưӧc chuyӇn qua (aBill). NӃu chúng ta
tìm thҩy mӝt kӃt quҧ khӟp, chúng ta gӑi remove() trên trình vòng lһp đӇ loҥi bӓ hóa đơn đó.
Cũng đơn giҧn, nhưng còn chưa phҧi là đơn giҧn hӃt mӭc. Mã dưӟi đây thӵc hiӋn cùng mӝt công
viӋc và dӉ đӑc hơn nhiӅu:

protected void removeBill(int aBill) {


bills.remove(new Integer(aBill));
}

Có thӇ bҥn sӁ không thưӡng xuyên gӑi remove() trên mӝt Iterator nhưng sӁ rҩt tӕt nӃu có
công cө đó khi bҥn cҫn nó.

Lúc này, chúng ta có thӇ loҥi bӓ chӍ mӝt hóa đơn riêng lҿ mӛi lҫn khӓi Wallet. SӁ là tӕt hơn nӃu
sӱ dөng sӭc mҥnh cӫa mӝt List đӇ giúp chúng ta loҥi bӓ nhiӅu hóa đơn cùng mӝt lúc, như sau:

public void spendËoney(List bills) {


this.wallet.removeBills(bills);
}

Chúng ta cҫn phҧi thêm removeBills() vào wallet cӫa chúng ta đӇ thӵc hiӋn viӋc này. Hãy
thӱ mã dưӟi đây:
protected void removeBills(List billsToRemove) {
this.bills.removeAll(bills);
}

Đây là viӋc triӇn khai thӵc hiӋn dӉ dàng nhҩt mà chúng ta có thӇ sӱ dөng. Chúng ta gӑi
removeAll() trên List các hoá đơn cӫa chúng ta, chuyӇn qua mӝt Collection. Sau đó phương
thӭc này loҥi bӓ tҩt cҧ các phҫn tӱ khӓi danh sách có trong Collection. Hãy thӱ chҥy mã dưӟi
đây:

List someBills = new ArrayList();


someBills.add(new Integer(1));
someBills.add(new Integer(2));

Adult anAdult = new Adult();


anAdult.acceptËoney(1);
anAdult.acceptËoney(1);
anAdult.acceptËoney(2);

List billsToRemove = new ArrayList();


billsToRemove.add(new Integer(1));
billsToRemove.add(new Integer(2));

anAdult.spendËoney(someBills);
´ystem.out.println(anAdult.wallet.bills);

Các kӃt quҧ không phҧi là nhӳng gì mà chúng ta muӕn. Chúng ta đã kӃt thúc mà không còn hóa
đơn nào trong ví cҧ. Tҥi sao? Bӣi vì removeAll() loҥi bӓ tҩt cҧ các kӃt quҧ khӟp. Nói cách khác,
bҩt kǤ và tҩt cҧ các kӃt quҧ khӟp vӟi mӝt mөc trong List mà chúng ta chuyӇn cho phương thӭc
đӅu bӏ loҥi bӓ. Các hoá đơn thanh toán mà chúng ta đã chuyӇn cho phương thӭc có chӭa 1 và 2.
Ví cӫa chúng ta có chӭa hai sӕ 1 và mӝt sӕ 2. Khi removeAll() tìm kiӃm kӃt quҧ khӟp vӟi phҫn
tӱ sӕ 1, nó tìm thҩy hai kӃt quҧ khӟp và loҥi bӓ chúng cҧ hai. Đó không phҧi là nhӳng gì mà
chúng ta muӕn! Chúng ta cҫn thay đәi mã cӫa chúng ta trong removeBills() đӇ sӱa lҥi điӅu
này:

protected void removeBills(List billsToRemove) {


Iterator iterator = billsToRemove.iterator();
while (iterator.hasNext()) {
this.bills.remove(iterator.next());
}
}

Mã này chӍ loҥi bӓ mӝt kӃt quҧ khӟp riêng rӁ, chӭ không phҧi là tҩt cҧ các kӃt quҧ khӟp. Nhӟ
cҭn thұn vӟi removeAll().

VӅ đҫu trang
TriӇn khai thӵc hiӋn tұp hӧp

Có hai triӇn khai thӵc hiӋn Tүp hӥp (Set) thưӡng đưӧc sӱ dөng phә biӃn:

KÊ Hash´et, không đҧm bҧo thӭ tӵ vòng lһp.


KÊ Tree´et, bҧo đҧm thӭ tӵ vòng lһp.

Các tài liӋu hưӟng dүn ngôn ngӳ Java gӧi ý rҵng bҥn sӁ đi đӃn chӛ sӱ dөng triӇn khai thӵc hiӋn
thӭ nhҩt trong hҫu hӃt các trưӡng hӧp. Nói chung, nӃu bҥn cҫn phҧi chҳc chҳn rҵng các phҫn tӱ
trong ´et cӫa bҥn xӃp theo mӝt thӭ tӵ nhҩt đӏnh nào đó khi bҥn duyӋt qua nó bҵng mӝt trình
vòng lһp, thì hãy sӱ dөng triӇn khai thӵc hiӋn thӭ hai. NӃu không, sӱ dөng cách thӭ nhҩt. Thӭ tӵ
cӫa các phҫn tӱ trong mӝt Tree´et (có thӵc hiӋn giao diӋn ´orted´et) đưӧc gӑi là  
V V (natural ordering); điӅu này có nghĩa là, hҫu hӃt mӑi trưӡng hӧp, bҥn sӁ có khҧ năng sҳp
xӃp các phҫn tӱ dӵa trên phép so sánh equals().

Giҧ sӱ rҵng mӛi Adult có mӝt tұp hӧp các biӋt hiӋu. Chúng ta thӵc sӵ không quan tâm đӃn
chúng đưӧc sҳp đһt thӃ nào, nhưng các bҧn sao sӁ không có ý nghĩa. Chúng ta có thӇ sӱ dөng
mӝt Hash´et đӇ lưu giӳ chúng. Trưӟc tiên, chúng ta thêm mӝt biӃn cá thӇ:

protected ´et nicknames = new Hash´et();

Sau đó chúng ta thêm mӝt phương thӭc đӇ thêm biӋt hiӋu vào ´et:

public void addNickname(´tring aNickname) {


nicknames.add(aNickname);
}

Bây giӡ hãy thӱ chҥy mã này:

Adult anAdult = new Adult();


anAdult.addNickname("Bobby");
anAdult.addNickname("Bob");
anAdult.addNickname("Bobby");
´ystem.out.println(anAdult.nicknames);

Bҥn sӁ thҩy chӍ có mӝt Bobby đơn lҿ xuҩt hiӋn trên màn hình.

VӅ đҫu trang

Các triӇn khai thӵc hiӋn Ëap

Ëap (Ánh xҥ) là mӝt tұp hӧp các cһp khóa - giá trӏ. Nó không thӇ chӭa các khóa giӕng hӋt nhau.
Mӛi khóa phҧi ánh xҥ tӟi mӝt giá trӏ đơn lҿ, nhưng giá trӏ đó có thӇ là bҩt kǤ kiӇu gì. Bҥn có thӇ
nghĩ vӅ mӝt ánh xҥ như là List có đһt tên. Hãy tưӣng tưӧng mӝt List trong đó mӛi phҫn tӱ có
mӝt tên mà bҥn có thӇ sӱ dөng đӇ trích ra phҫn tӱ đó trӵc tiӃp. Khóa có thӇ là bҩt cӭ cái gì kiӇu
Object, giӕng như giá trӏ. Mӝt lҫn nӳa, điӅu đó có nghĩa là bҥn không thӇ lưu trӳ các giá trӏ kiӇu
nguyên thӫy (primitive) trӵc tiӃp vào trong mӝt Ëap (bҥn có ghét các giá trӏ kiӇu nguyên thӫy
không đҩy ?). Thay vào đó, bҥn phҧi sӱ dөng các lӟp bao gói kiӇu nguyên thӫy đӇ lưu giӳ các
giá trӏ đó.

Mһc dù đây là mӝt chiӃn lưӧc tài chính mҥo hiӇm, chúng ta sӁ cung cҩp cho mӛi Adult mӝt tұp
hӧp các thҿ tín dөng đơn giҧn nhҩt có thӇ chҩp nhұn đưӧc. Mӛi thҿ sӁ có mӝt tên và mӝt sӕ dư
(ban đҫu là 0). Trưӟc tiên, chúng ta thêm mӝt biӃn cá thӇ:

protected Ëap creditCards = new HashËap();

Sau đó chung ta thêm mӝt phương thӭc đӇ bә sung thêm mӝt thҿ tín dөng (CreditCard)tӟi Ëap:

public void addCreditCard(´tring aCardName) {


creditCards.put(aCardName, new Double(0));
}

Giao diӋn cӫa Ëap khác vӟi các giao diӋn cӫa các sưu tұp khác. Bҥn gӑi put() vӟi mӝt khóa và
mӝt giá trӏ đӇ thêm mӝt mөc vào ánh xҥ. Bҥn gӑi get() vӟi khóa đӇ trích ra mӝt giá trӏ. Chúng ta
sӁ làm viӋc này trong mӝt phương thӭc đӇ hiӇn thӏ sӕ dư cӫa mӝt thҿ:

public double getBalanceFor(´tring cardName) {


Double balance = (Double) creditCards.get(cardName);
return balance.doubleValue();
}

Tҩt cҧ nhӳng gì còn lҥi là thêm phương thӭc charge() đӇ cho phép cӝng thêm vào sӕ dư cӫa
chúng ta:

public void charge(´tring cardName, double amount) {


Double balance = (Double) creditCards.get(cardName);
double primitiveBalance = balance.doubleValue();
primitiveBalance += amount;
balance = new Double(primitiveBalance);

creditCards.put(cardName, balance);
}

Bây giӡ hãy thӱ chҥy mã dưӟi đây, nó sӁ hiӇn thӏ cho bҥn 19.95 trên màn hình.

Adult anAdult = new Adult();


anAdult.addCreditCard("Visa");
anAdult.addCreditCard("ËasterCard");
anAdult.charge("Visa", 19.95);
adAdult.showBalanceFor("Visa");

Mӝt thҿ tín dөng điӇn hình có mӝt tên, mӝt sӕ tài khoҧn, mӝt hҥn mӭc tín dөng và mӝt sӕ dư.
Mӛi mөc trong mӝt Ëap chӍ có thӇ có mӝt khóa và mӝt giá trӏ. Các thҿ tín dөng rҩt đơn giҧn cӫa
chúng ta rҩt phù hӧp, bӣi vì chúng chӍ có mӝt tên và mӝt sӕ dư hiӋn tҥi. Chúng ta có thӇ làm cho
phӭc tҥp hơn bҵng cách tҥo ra mӝt lӟp đưӧc gӑi là CreditCard, vӟi các biӃn cá thӇ dành cho tҩt
cҧ các đһc tính cӫa mӝt thҿ tín dөng, sau đó lưu trӳ các cá thӇ cӫa lӟp này như các giá trӏ cho các
mөc trong Ëap cӫa chúng ta.

Có mӝt sӕ khía cҥnh thú vӏ khác vӅ giao diӋn Ëap đӇ trình bày trưӟc khi chúng ta đi tiӃp (đây
không phҧi là mӝt danh sách đҫy đӫ):

w 
 

containsKey() Trҧ lӡi Ëap có chӭa khóa đã cho hay không.

containsValue() Trҧ lӡi Ëap có chӭa giá trӏ đã cho hay không.

key´et() Trҧ vӅ mӝt ´et tұp hӧp các khóa.

values() Trҧ vӅ mӝt ´et tұp hӧp các giá trӏ.

entry´et()
Trҧ vӅ mӝt ´et tұp hӧp các cһp khóa - giá trӏ, đưӧc đӏnh nghĩa như là các cá
thӇ cӫa các Ëap.Entry.

remove() Cho phép bҥn loҥi bӓ giá trӏ cho mӝt khóa đã cho.

isEmpty() Trҧ lӡi Ëap có rӛng không (rӛng có nghĩa là, không chӭa khóa nào).

Mӝt sӕ trong các phương thӭc này, chҷng hҥn như isEmpty() chӍ là đӇ cho tiӋn thôi, nhưng mӝt
sӕ là rҩt quan trӑng. Ví dө, cách duy nhҩt đӇ thӵc hiӋn vòng lһp qua các phҫn tӱ trong mӝt Ëap là
thông qua mӝt trong các tұp hӧp có liên quan (tұp hӧp các khóa, các giá trӏ, hoһc các cһp khóa-
giá trӏ).

VӅ đҫu trang

Lӟp Các sưu tұp (Collections)

Khi bҥn đang sӱ dөng khung công tác các sưu tұp Java, bҥn cҫn phҧi nҳm đưӧc nhӳng gì có sҹn
trong lӟp Collections. Lӟp này gӗm có mӝt kho lưu trӳ các phương thӭc tĩnh đӇ hӛ trӧ các
thao tác trên sưu tұp. Chúng tôi sӁ không trình bày tҩt cҧ chúng ӣ đây, bӣi vì bҥn có thӇ tӵ mình
đӑc API, nhưng chúng tôi sӁ trình bày hai phương thӭc thưӡng xuyên xuҩt hiӋn trong mã Java:

KÊ copy()
KÊ sort()

Phương thӭc đҫu tiên cho phép bҥn sao chép các nӝi dung cӫa mӝt sưu tұp này tӟi mӝt sưu tұp
khác, như sau:

List source = new ArrayList();


source.add("one");
source.add("two");
List target = new ArrayList();
target.add("three");
target.add("four");

Collections.copy(target, source);
´ystem.out.println(target);

Mã này sao chép tӯ nguӕn (source) vào đích (target). Đích phҧi có cùng kích thưӟc như nguӗn,
vì thӃ bҥn không thӇ sao chép mӝt List vào mӝt List rӛng.

Phương thӭc sort() sҳp xӃp các phҫn tӱ theo thӭ tӵ tӵ nhiên cӫa chúng. Tҩt cҧ các phҫn tӱ phҧi
triӇn khai thӵc hiӋn giao diӋn Comparable sao cho chúng có thӇ V  V . Các lӟp có
sҹn giӕng như ´tring đã thӵc hiӋn điӅu này. Vì vұy, đӕi vӟi mӝt tұp hӧp các chuӛi ký tӵ, chúng
ta có thӇ sҳp xӃp chúng theo thӭ tӵ tăng dүn theo kiӇu biên soҥn tӯ điӇn bҵng mã sau đây:

List strings = new ArrayList();


strings.add("one");
strings.add("two");
strings.add("three");
strings.add("four");

Collections.sort(strings);
´ystem.out.println(strings);

Bҥn sӁ nhұn đưӧc [four, one, three, two] trên màn hình. Nhưng bҥn có thӇ sҳp xӃp các lӟp
mà bҥn tҥo ra như thӃ nào? Chúng ta có thӇ làm điӅu này cho Adult. Trưӟc tiên, chúng ta làm
cho lӟp Adult có thӇ so sánh lүn nhau:

public class Adult extends Person implements Comparable {


...
}

Sau đó, chúng ta ghi đè compareTo() đӇ so sánh hai cá thӇ Adult Chúng ta sӁ duy trì viӋc so
sánh rҩt đơn giҧn đӇ làm ví dө, do đó nó làm rҩt ít viӋc:
public int compareTo(Object other) {
final int LE´´ THAN = -1;
final int EQUAL = 0;
final int GREATER THAN = 1;

Adult otherAdult = (Adult) other;


if ( this == otherAdult ) return EQUAL;

int comparison = this.firstname.compareTo(otherAdult.firstname);


if (comparison != EQUAL) return comparison;

comparison = this.lastname.compareTo(otherAdult.lastname);
if (comparison != EQUAL) return comparison;

return EQUAL;
}

Bҩt kǤ sӕ nào nhӓ hơn 0 có nghĩa là "bé hơn", và -1 là giá trӏ thích hӧp đӇ sӱ dөng. Tương tӵ, 1
là thuұn tiӋn đӇ dành cho "lӟn hơn". Như bҥn có thӇ thҩy, 0 có nghĩa là "bҵng nhau". So sánh hai
đӕi tưӧng theo cách này rõ ràng là mӝt quá trình thӫ công. Bҥn cҫn phҧi đi qua các biӃn cá thӇ và
so sánh tӯng biӃn. Trong trưӡng hӧp này, chúng ta so sánh tên và hӑ và sҳp xӃp thӵc tӃ theo hӑ.
Nhưng bҥn nên biӃt, tҥi sao ví dө cӫa chúng ta lҥi rҩt đơn giҧn. Mӛi Adult có nhiӅu hơn là chӍ
tên và hӑ. NӃu chúng ta muӕn làm mӝt phép so sánh sâu hơn, chúng ta sӁ phҧi so sánh các
Wallet cӫa mӛi Adult đӇ xem xem chúng có bҵng nhau không, nghĩa là chúng ta sӁ phҧi triӇn
khai thӵc hiӋn compareTo() trên Wallet và phҫn còn lҥi. Ngoài ra, đӇ thұt chính xác khi so
sánh, bҩt cӭ khi nào bҥn ghi đè compareTo(), bҥn cҫn phҧi chҳc chҳn là phép so sánh là tương
thích vӟi equals(). Chúng ta không triӇn khai thӵc hiӋn equals(), vì thӃ chúng ta không lo
lҳng vӅ viӋc tương thích vӟi nó, nhưng chúng ta có thӇ phҧi làm. Trong thӵc tӃ, tôi đã thҩy mã có
bao gӗm mӝt dòng như sau, trưӟc khi trҧ vӅ EQUAL:

assert this.equals(otherAdult) : "compareTo inconsistent with equals.";

Cách tiӃp cұn khác đӇ so sánh các đӕi tưӧng là trích thuұt toán trong compareTo() vào mӝt đӕi
tưӧng có kiӇu Trình so sánh (Comparator), sau đó gӑi Collections.sort() vӟi sưu tұp cҫn
sҳp xӃp và Comparator, như sau:

public class AdultComparator implements Comparator {

public int compare(Object object1, Object object2) {


final int LE´´ THAN = -1;
final int EQUAL = 0;
final int GREATER THAN = 1;

if ((object1 == null) ;amp;amp (object2 == null))


return EQUAL;
if (object1 == null)
return LE´´ THAN;
if (object2 == null)
return GREATER THAN;
Adult adult1 = (Adult) object1;
Adult adult2 = (Adult) object2;
if (adult1 == adult2)
return EQUAL;

int comparison = adult1.firstname.compareTo(adult2.firstname);


if (comparison != EQUAL)
return comparison;

comparison = adult1.lastname.compareTo(adult2.lastname);
if (comparison != EQUAL)
return comparison;

return EQUAL;
}
}

public class CommunityApplication {

public static void main(´tring[] args) {


Adult adult1 = new Adult();
adult1.setFirstname("Bob");
adult1.setLastname("´mith");

Adult adult2 = new Adult();


adult2.setFirstname("Al");
adult2.setLastname("Jones");

List adults = new ArrayList();


adults.add(adult1);
adults.add(adult2);

Collections.sort(adults, new AdultComparator());


´ystem.out.println(adults);
}
}

Bҥn sӁ thҩy "Al Jones" và "Bob Smith", theo thӭ tӵ đó, trong cӱa sә màn hình cӫa bҥn.

Có mӝt sӕ lý do thích đáng đӇ sӱ dөng cách tiӃp cұn thӭ hai. Các lý do kӻ thuұt vưӧt ra ngoài
phҥm vi cӫa hưӟng dүn này. Tuy nhiên, tӯ viӉn cҧnh cӫa phát triӇn hưӟng đӕi tưӧng, đây có thӇ
là mӝt ý tưӣng tӕt khi tách biӋt phҫn mã so sánh vào trong đӕi tưӧng khác, hơn là cung cҩp cho
mӛi Adult khҧ năng tӵ so sánh vӟi nhau. Tuy nhiên, vì đây thӵc sӵ là nhӳng gì mà equals()
thӵc hiӋn, mһc dù kӃt quҧ là toán tӱ boolean, có các lұp luұn thích hӧp ӫng hӝ cho cҧ hai cách
tiӃp cұn.

VӅ đҫu trang

Sӱ dөng các sưu tұp


Khi nào bҥn nên sӱ dөng mӝt kiӇu sưu tұp cө thӇ ? Đó là mӝt phán xét cҫn đӃn năng lӵc cӫa bҥn,
và chính vì thӃ mà bҥn hy vӑng sӁ đưӧc trҧ lương hұu hĩ khi là mӝt lұp trình viên.

Bҩt chҩp nhӳng gì mà nhiӅu chuyên gia tin tưӣng, có rҩt ít các quy tҳc chҳc chҳn và nhanh chóng
đӇ xác đӏnh cҫn sӱ dөng nhӳng lӟp nào trong mӝt tình huӕng đã cho nào đó. Theo kinh nghiӋm
cá nhân cӫa tôi, trong phҫn lӟn các lҫn khi sӱ dөng các sưu tұp, mӝt ArrayList hoһc mӝt
HashËap (hãy nhӟ, mӝt Ëap không thұt sӵ là mӝt sưu tұp) đӅu bӏ chơi khăm. Rҩt có khҧ năng,
bҥn cũng tӯng có trҧi nghiӋm như vұy. Dưӟi đây là mӝt sӕ quy tҳc ngón tay cái, mӝt sӕ là hiӇn
nhiên hơn nhӳng cái còn lҥi:

KÊ Khi bҥn nghĩ rҵng mình cҫn có mӝt sưu tұp, hãy bҳt đҫu vӟi mӝt List, sau đó cӭ đӇ cho
các mã sӁ báo cho bҥn biӃt có cҫn mӝt kiӇu khác không.
KÊ NӃu bҥn chӍ cҫn nhóm các thӭ gì đó, hãy sӱ dөng mӝt ´et.
KÊ NӃu thӭ tӵ trong vòng lһp là rҩt quan trӑng khi duyӋt qua mӝt sưu tұp, hãy sӱ dөng
Tree... mӝt hương vӏ khác cӫa sưu tұp, khi ӣ đó có sҹn.
KÊ Tránh sӱ dөng Vector, trӯ khi bҥn cҫn khҧ năng đӗng bӝ hóa cӫa nó.
KÊ Không nên lo lҳng vӅ viӋc tӕi ưu hóa cho đӃn khi (và trӯ khi) hiӋu năng trӣ thành mӝt
vҩn đӅ.

Các bӝ sưu tұp là mӝt trong nhӳng khía cҥnh mҥnh mӁ nhҩt cӫa ngôn ngӳ Java. Đӯng ngҥi khi
sӱ dөng chúng, nhưng cҫn cҧnh giác vӅ các vө "Tìm ra rӗi" (gotchas). Ví dө, có mӝt cách thuұn
tiӋn đӇ chuyӇn đәi tӯ mӝt Array thành mӝt ArrayList:

Adult adult1 = new Adult();


Adult adult2 = new Adult();
Adult adult3 = new Adult();

List immutableList = Arrays.asList(new Object[] { adult1, adult2, adult3 });


immutableList.add(new Adult());

Mã này đưa ra mӝt UnsupportedOperationException, vì List đưӧc Arrays.asList() trҧ vӅ


là không thay đәi đưӧc. Bҥn không thӇ thêm mӝt phҫn tӱ mӟi vào mӝt List không thay đәi. Hãy
đӇ ý.

You might also like