﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-Java Learner</title><link>http://www.blogjava.net/Iamforward/</link><description>基础的重要性</description><language>zh-cn</language><lastBuildDate>Thu, 07 May 2026 06:28:42 GMT</lastBuildDate><pubDate>Thu, 07 May 2026 06:28:42 GMT</pubDate><ttl>60</ttl><item><title>Filter collections</title><link>http://www.blogjava.net/Iamforward/archive/2007/09/28/149320.html</link><dc:creator>Chris Huang</dc:creator><author>Chris Huang</author><pubDate>Fri, 28 Sep 2007 10:02:00 GMT</pubDate><guid>http://www.blogjava.net/Iamforward/archive/2007/09/28/149320.html</guid><wfw:comment>http://www.blogjava.net/Iamforward/comments/149320.html</wfw:comment><comments>http://www.blogjava.net/Iamforward/archive/2007/09/28/149320.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Iamforward/comments/commentRss/149320.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Iamforward/services/trackbacks/149320.html</trackback:ping><description><![CDATA[<p><span style="font-family: Tahoma"></span>&nbsp;</p>
<h1>Filter collections</h1>
<h3>A simple generic mechanism for filtering collections</h3>
<p class="byline">By&nbsp;David Rappoport,&nbsp;JavaWorld.com,&nbsp;10/18/04<br />
</p>
<!-- CONTENT GOES HERE-->
<p class="first">Track: http://www.javaworld.com/javaworld/jw-10-2004/jw-1018-filter.html<br />
Often, you must iterate through a collection of objects and filter them based on a number of criteria. The JDK supplies a useful mechanism for sorting collections, namely the <code>Comparator</code> interface. However, the JDK lacks a mechanism for filtering collections. </p>
<p>This article describes a simple mechanism consisting of only one class and one interface that allows you to filter collections quickly and neatly. When searching a collection, the described mechanism offers the same functionality as a SQL <code>SELECT</code> statement. Its underlying concept is its separation of responsibilities between iterating through the collection and filtering the objects in the collection. </p>
<p>The approach presented here has the following benefits:</p>
<ol>
    <li>Reuse of a central filtering component produces cleaner code
    <li>Reuse of common filtering components generates less error-prone code
    <li>Separating the iteration logic from the filtering logic allows you to add or remove filters at will without affecting any other code
    <li>Possible performance gains with large collections and multiple criteria </li>
</ol>
<br />
<br />
<h3>The problem</h3>
<p>Imagine a search mask where a user can choose among numerous different criteria to search for cars. Approaching this task simply, the developer must iterate through the collection multiple times. In each iteration, he must execute certain logic on each object in the collection to decide whether it fits the criteria. Usually, the result of this process is messy code that is both hard to read and maintain. </p>
<h3>The solution</h3>
<p>We define a class called <code>CollectionFilter</code> and an interface called <code>FilterCriteria</code>. </p>
<p><code>FilterCriteria</code> defines only one method: <code>public boolean passes(Object o)</code>. In this method, an object in the collection must pass a certain test. If it passes the test, the method returns true, otherwise, false. </p>
<p><code>CollectionFilter</code> now takes any number of <code>FilterCriteria</code> as input. You then call the <code>public void filter(Collection)</code> method, which applies all <code>FilterCriteria</code> to the supplied collection and removes any object in the collection that doesn't pass all <code>FilterCriteria</code>. </p>
<p>The <code>CollectionFilter</code> class also defines a <code>public Collection filterCopy(Collection)</code> method, which completes the same task as the <code>filter(Collection)</code> method, but on a copy of the original filter. </p>
<p>That's it!</p>
<p>As you may have noticed, this solution borrows some ideas from the Chain of Responsibility design pattern and applies them to a collection. </p>
<p>The following class diagram illustrates the classes and interfaces and how they relate to each other.</p>
<center>
<p><a href="http://www.javaworld.com/javaworld/jw-10-2004/images/jw-1018-filter.gif" target="new_window" alt="Class diagram. Click on thumbnail to view full-sized image."><img height="280" alt="" src="http://www.javaworld.com/javaworld/jw-10-2004/images/jw-1018-filter-thumb.gif" width="350" /></a></p>
<p><strong>Class diagram. Click on thumbnail to view full-sized image.</strong></p>
</center>
<h3>Simple example</h3>
<p>Let's look at an example: Class <code>Car</code> has three attributes: String <code>color</code>, double <code>maxSpeed</code>, boolean <code>fourWheelDrive</code>. </p>
<p>Your application allows searching for cars based on these criteria. The user can enter the color she prefers. She can also provide the maximum speed she wants the car to have and also whether the car should support four-wheel drive. </p>
<p>We now create three filter classes, one for each criteria the user can choose.</p>
<ol>
    <li>Write the <code>FilterCriteria</code> implementations:<br />
    <br />
    <div id="codewrap">
    <div id="codewrap51">
    <pre>class ColorFilterCriteria implements FilterCriteria{
    private String color;
    public boolean passes(Object o){
    return ((Car)o).getColor().equals(color);
    }
    }
    class MaxSpeedFilterCriteria implements FilterCriteria{
    private int maxSpeed;
    public boolean passes(Object o){
    return ((Car)o).getMaxSpeed() &gt;= maxSpeed;
    }
    }
    class FourWheelDriveFilterCriteria implements FilterCriteria{
    private boolean fourWheelDriveRequired;
    private boolean fourWheelDriveAllowed;
    public boolean passes(Object o){
    return fourWheelDriveRequired?((Car)o).isFourWheelDrive():fourWheelDriveAllowed?true:!
    ((Car)o).isFourWheelDrive();
    }
    }
    </pre>
    </div>
    </div>
    <li>Then add these <code>FilterCriteria</code> to a <code>CollectionFilter</code>:<br />
    <br />
    <div id="codewrap">
    <div id="codewrap57">
    <pre>CollectionFilter collectionFilter = new CollectionFilter();
    filter.addFilterCriteria(new ColorFilterCriteria(color));
    filter.addFilterCriteria(new MaxSpeedFilterCriteria(maxSpeed));
    filter.addFilterCriteria(new FourWheelDriveFilterCriteria(fourWheelDriveRequired, fourWheelDriveAllowed));
    </pre>
    </div>
    </div>
    <li>Now filter:<br />
    <br />
    <div id="codewrap">
    <div id="codewrap61">
    <pre>collectionFilter.filter(carCollection);
    </pre>
    </div>
    </div>
    </li>
</ol>
<br />
<br />
<h3>Technicalities</h3>
<p>As you may have realized, similar to the <code>compare(Object o1, Object o2)</code> method in the <code>Comparator</code> interface, the <code>passes(Object o)</code> method in the <code>FilterCriteria</code> interface takes an object of type <code>Object</code> as input. This means you must cast the object to the type you want to work with and ensure your collection only contains an object of that type. If this is not certain, you can use <code>instanceof</code> to test whether the specific object is of that type. </p>
<p>Sometimes, you might prefer not to define a separate class for each <code>FilterCriteria</code>. The use of an anonymous inner class suggests itself in such cases. </p>
<p>To keep the solution simple, I refrained from adding OR functionality to this filter. In other words, every time you add a <code>FilterCriteria</code> to your <code>CollectionFilter</code>, this can be compared to an AND in a SQL statement, since you're adding another condition. However, you can easily add OR-like functionality within one <code>FilterCriteria</code>. For example: </p>
<div id="codewrap">
<div id="codewrap80">
<pre>class EitherOrColorFilterCriteria implements FilterCriteria{
private String color1;
private String color2;
public boolean passes(Object o){
return ((Car)o).getColor().equals(color1) || ((Car)o).getColor().equals(color2);
}
}
</pre>
</div>
</div>
<br />
<h3>&nbsp;</h3>
<img src ="http://www.blogjava.net/Iamforward/aggbug/149320.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Iamforward/" target="_blank">Chris Huang</a> 2007-09-28 18:02 <a href="http://www.blogjava.net/Iamforward/archive/2007/09/28/149320.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>