View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections4.functors;
18  
19  import java.io.Serializable;
20  import java.util.Comparator;
21  import java.util.Objects;
22  
23  import org.apache.commons.collections4.Predicate;
24  
25  /**
26   * Predicate that compares the input object with the one stored in the predicate using a comparator.
27   * In addition, the comparator result can be evaluated in accordance to a supplied criterion value.
28   *
29   * <p>In order to demonstrate the use of the predicate, the following variables are declared:</p>
30   *
31   * <pre>
32   * Integer ONE = Integer.valueOf(1);
33   * Integer TWO = Integer.valueOf(2);
34   *
35   * Comparator comparator = new Comparator() {
36   *
37   *     public int compare(Object first, Object second) {
38   *         return ((Integer) second) - ((Integer) first);
39   *     }
40   *
41   * };
42   * </pre>
43   *
44   * <p>Using the declared variables, the {@code ComparatorPredicate} can be used in the
45   * following way:</p>
46   *
47   * <pre>
48   * ComparatorPredicate.comparatorPredicate(ONE, comparator).evaluate(TWO);
49   * </pre>
50   *
51   * <p>The input variable {@code TWO} in compared to the stored variable {@code ONE} using
52   * the supplied {@code comparator}. This is the default usage of the predicate and will return
53   * {@code true} if the underlying comparator returns {@code 0}. In addition to the default
54   * usage of the predicate, it is possible to evaluate the comparator's result in several ways. The
55   * following {@link Criterion} enumeration values are provided by the predicate:
56   * </p>
57   *
58   * <ul>
59   *     <li>EQUAL</li>
60   *     <li>GREATER</li>
61   *     <li>GREATER_OR_EQUAL</li>
62   *     <li>LESS</li>
63   *     <li>LESS_OR_EQUAL</li>
64   * </ul>
65   *
66   * <p>The following examples demonstrates how these constants can be used in order to manipulate the
67   * evaluation of a comparator result.</p>
68   *
69   * <pre>
70   * ComparatorPredicate.comparatorPredicate(ONE, comparator,<b>ComparatorPredicate.Criterion.GREATER</b>).evaluate(TWO);
71   * </pre>
72   *
73   * <p>The input variable TWO is compared to the stored variable ONE using the supplied {@code comparator}
74   * using the {@code GREATER} evaluation criterion constant. This instructs the predicate to
75   * return {@code true} if the comparator returns a value greater than {@code 0}.</p>
76   *
77   * @since 4.0
78   */
79  public class ComparatorPredicate<T> implements Predicate<T>, Serializable {
80  
81      public enum Criterion {
82          EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL,
83      }
84  
85      private static final long serialVersionUID = -1863209236504077399L;
86  
87      // Instance variables:
88  
89      /**
90       * Factory to create the comparator predicate
91       *
92       * @param <T> the type that the predicate queries
93       * @param object  the object to compare to
94       * @param comparator  the comparator to use for comparison
95       * @return the predicate
96       * @throws NullPointerException if comparator is null
97       */
98      public static <T> Predicate<T> comparatorPredicate(final T object, final Comparator<T> comparator) {
99          return comparatorPredicate(object, comparator, Criterion.EQUAL);
100     }
101 
102     /**
103      * Factory to create the comparator predicate
104      *
105      * @param <T> the type that the predicate queries
106      * @param object  the object to compare to
107      * @param comparator  the comparator to use for comparison
108      * @param criterion  the criterion to use to evaluate comparison
109      * @return the predicate
110      * @throws NullPointerException if comparator or criterion is null
111      */
112     public static <T> Predicate<T> comparatorPredicate(final T object, final Comparator<T> comparator,
113                                                        final Criterion criterion) {
114         return new ComparatorPredicate<>(object, Objects.requireNonNull(comparator, "comparator"),
115                 Objects.requireNonNull(criterion, "criterion"));
116     }
117 
118     /** The internal object to compare with */
119     private final T object;
120 
121     /** The comparator to use for comparison */
122     private final Comparator<T> comparator;
123 
124     /** The comparison evaluation criterion to use */
125     private final Criterion criterion;
126 
127     /**
128      * Constructor that performs no validation.
129      * Use {@code comparatorPredicate} if you want that.
130      *
131      * @param object  the object to compare to
132      * @param comparator  the comparator to use for comparison
133      * @param criterion  the criterion to use to evaluate comparison
134      */
135     public ComparatorPredicate(final T object, final Comparator<T> comparator, final Criterion criterion) {
136         this.object = object;
137         this.comparator = comparator;
138         this.criterion = criterion;
139     }
140 
141     /**
142      * Evaluates the predicate. The predicate evaluates to {@code true} in the following cases:
143      *
144      * <ul>
145      * <li>{@code comparator.compare(object, input) == 0 &amp;&amp; criterion == EQUAL}</li>
146      * <li>{@code comparator.compare(object, input) &lt; 0 &amp;&amp; criterion == LESS}</li>
147      * <li>{@code comparator.compare(object, input) &gt; 0 &amp;&amp; criterion == GREATER}</li>
148      * <li>{@code comparator.compare(object, input) &gt;= 0 &amp;&amp; criterion == GREATER_OR_EQUAL}</li>
149      * <li>{@code comparator.compare(object, input) &lt;= 0 &amp;&amp; criterion == LESS_OR_EQUAL}</li>
150      * </ul>
151      *
152      * @see org.apache.commons.collections4.Predicate#evaluate(Object)
153      * @see java.util.Comparator#compare(Object first, Object second)
154      *
155      * @param target  the target object to compare to
156      * @return {@code true} if the comparison succeeds according to the selected criterion
157      * @throws IllegalStateException if the criterion is invalid (really not possible)
158      */
159     @Override
160     public boolean evaluate(final T target) {
161 
162         boolean result = false;
163         final int comparison = comparator.compare(object, target);
164         switch (criterion) {
165         case EQUAL:
166             result = comparison == 0;
167             break;
168         case GREATER:
169             result = comparison > 0;
170             break;
171         case LESS:
172             result = comparison < 0;
173             break;
174         case GREATER_OR_EQUAL:
175             result = comparison >= 0;
176             break;
177         case LESS_OR_EQUAL:
178             result = comparison <= 0;
179             break;
180         default:
181             throw new IllegalStateException("The current criterion '" + criterion + "' is invalid.");
182         }
183 
184         return result;
185     }
186 }