You need to prioritize objects: removing higher priority objects from a Collection
before lower priority
objects.
Use a PriorityBuffer
to hold objects to be prioritized. Objects will be
removed from this Buffer
according to
a priority generated with a Comparator
. Whenever the remove( )
method is called on this Buffer
implementation, a PriorityBuffer
uses the Comparator
to sort its contents, returning the
element of greatest priority. Using a PriorityBuffer
without a Comparator
causes the buffer to prioritize
objects by natural order, casting each object to Comparable
and comparing objects with the
compareTo( )
method; all objects must
implement the Comparable
interface if
no Comparator
is supplied. The
following example demonstrates the use of a PriorityBuffer
without supplying a Comparator
:
import java.util.*; import org.apache.commons.collections.Buffer; import org.apache.commons.collections.buffers.PriorityBuffer; // Create a PriorityBuffer with no Comparator Buffer priority = new PriortyBuffer( ); priority.add( new Long( 2 ) ); priority.add( new Long( 1 ) ); priority.add( new Long( 20 ) ); priority.add( new Long( 7 ) ); priority.add( new Long( 18 ) ); priority.add( new Long( 1 ) ); // Print the results in priority order Iterator priorityIterator = priority.iterator( ); while( priorityIterator.hasNext( ) ) { Long value = (Long) priority.next( ); System.out.prinltn( "Value: " + value ); }
The previous example removes values from the buffer based on a natural order, and the following output is produced:
Value: 20 Value: 18 Value: 7 Value: 2 Value: 1 Value: 1
A PriorityBuffer
, like all
Buffer
implementations, is defined by
the logic to select which object to remove. If you've ever visited an
emergency room, you are already familiar with the inner workings of the
PriorityBuffer
. When a patient enters
the emergency room, his or her condition is evaluated by a nurse who
then assigns a severity. When a doctor moves to the next patient, she
chooses the next patient based on severity and how long each patient has
been waiting. A patient with a critical, life-threatening condition will
be treated before an individual with a headache—the critical patient has
a higher priority in the Buffer
.
The following example models an emergency waiting room with a
PriorityBuffer
. Assume that you have
a Patient
bean with name
, severity
, and checkIn
properties, which is defined in Example 5-5. A patient's severity is a
number from 0 to 10, 0 being the lowest severity and 10 being the
highest. A critical patient would be assigned a priority of 10, and a
patient with a bad cold would be assigned a severity of 0. A patient
also has a checkIn
time: this is the
time he is admitted to the waiting room, and it is used as a tie-breaker
to determine priority when two patients have the same severity
.
Example 5-5. A Patient object
package com.discursive.jccook.collections.buffers; public class Patient { private String name; private Integer severity; private Date checkIn; public class Patient( ) {} public String getName( ) { return name; } public void setName(String name) { this.name = name; } public Integer getSeverity( ) { return severity; } public void setSeverity(Integer severity) { this.severity = severity; } public Date getCheckIn( ) { return checkIn; } public void setCheckIn(Date checkIn) { this.checkIn = checkIn; } }
The PatientPriorityComparator
in Example 5-6
prioritizes patients by severity of condition and time since check-in. A
patient with a more severe condition takes priority over a patient with
a less severe condition who has been waiting longer, and, if two
patients have the same severity, the one who has been waiting longer
gets a higher priority. If this Comparator
is used to sort an array of
Patient
objects, the most critical
patient would be at the last index, and the least critical would be at
the first index.
Example 5-6. A Comparator to sort Patient objects by priority
package com.discursive.jccook.collections.buffers; import java.util.Comparator; public PatientPriorityComparator implements Comparator { public int compare(Object o1, Object o2) { int comparison = -1; if( o1 instanceof Patient && o2 instanceof Patient ) { Patient p1 = (Patient) o1; Patient p2 = (Patient) o2; comparison = p1.getSeverity( ).compareTo( p2.getSeverity( ) ); if( comparison == 0 ) { comparison = p1.getCheckIn( ).compareTo( p2.getCheckIn( ) ); } } return comparison; } }
When using the PriorityBuffer
with a PatientPriorityComparator
,
Patient
objects are added to the
Buffer
and remove( )
returns the Patient
with the highest priority. Using a
PriorityBuffer
means that you do not
need to worry about constantly resorting a Collection
by priority; this logic is
completed automatically every time an object is removed from the
Buffer
. In other words, you are
delegating responsibility to a Buffer
; it takes care of the sorting and
selecting on an as-needed basis.
Example 5-7 adds three
Patient
objects to a PriorityBuffer
: John Doe 1 has an ear ache,
John Doe 2 has a broken back, and Jane Doe 3 has a concussion. Both John
2 and Jane 3 have serious conditions, and, since John 2 checked in
before Jane 3, John 2 has a higher priority than Jane 3. John 1's
condition is not nearly as critical; therefore, his priority is much
lower, and he is treated last.
Example 5-7. Using a prioritizing buffer
package com.discursive.jccook.collections.buffers; public class WaitingRoomApp { public static void main(String[] args) { WaitingRoomApp example = new WaitingRoomApp( ); example.start( ); } public void start( ) { Buffer patients = new PriorityBuffer( new PatientPriorityComparator( ) ); Patient johnDoe1 = new Patient( ); johnDoe1.setName( "John Doe 1" ); johnDoe1.setSeverity( new Integer( 7 ) ); johnDoe1.setCheckIn( new Date( ) ); patients.add( johnDoe1 ); Patient johnDoe2 = new Patient( ); johnDoe2.setName( "John Doe 2" ); johnDoe2.setSeverity( new Integer( 9 ) ); johnDoe2.setCheckIn( new Date( ) ); patients.add( johnDoe2 ); Patient janeDoe3 = new Patient( ); janeDoe3.setName( "Jane Doe 3" ); janeDoe3.setSeverity( new Integer( 9 ) ); janeDoe3.setCheckIn( new Date( ) ); patients.add( janeDoe3 ); while( patients.size( ) > 0 ) { Patient patient = (Patient) patients.remove( ); System.out.println( "Patient: " + patient.getName( ) ); } } }
As each Patient
is treated, the
patient's name is printed to the console:
Patient: John Doe 2 Patient: Jane Doe 3 Patient: John Doe 1
A PriorityBuffer
in Commons Collections is
analogous to a PriorityQueue
in Java
5.0. For information about PriorityQueue
and other important changes to
the Collections framework in Java 5.0, see http://java.sun.com/j2se/1.5.0/docs/api/index.html.