1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sf.collections15.functors.closure;
17
18 import net.sf.collections15.Closure;
19 import net.sf.collections15.Predicate;
20
21 import java.io.Serializable;
22
23 /***
24 * <code>Closure</code> decorator that executes a specified <code>Closure</code>
25 * repeatedly until a condition is met, like a <code>do-while</code> or
26 * <code>while</code> loop.
27 *
28 * @author Stephen Colebourne
29 * @author Chris Lambrou (port to Java 5.0)
30 * @since Collections15 1.0
31 */
32 public class WhileClosure <E> implements Closure<E>, Serializable
33 {
34
35 static final long serialVersionUID = -7331385147116164115L;
36
37 /***
38 * The test condition.
39 */
40 private final Predicate<? super E> predicate;
41
42 /***
43 * The <code>Closure</code> to execute.
44 */
45 private final Closure<? super E> closure;
46
47 /***
48 * Flag indicating whether or not to effect a <code>while</code> loop or a
49 * <code>do-while</code>. If <code>true</code>, the condition is evaluated
50 * after the first execution of the decorated <code>closure</code>. If
51 * <code>false</code>, the condition is evaluated before the first execution
52 * of the decorated <code>Closure</code>.
53 */
54 private final boolean doLoop;
55
56 /***
57 * Returns a <code>WhileClosure</code> instance that decorates the specified
58 * <code>Closure</code> using the specified <code>Predicate</code>
59 * condition.
60 *
61 * @param predicate The <code>Predicate</code> used to determine when the
62 * loop should terminate.
63 * @param closure The <code>Closure</code> executed in the loop.
64 * @param doLoop Indicates whether to effect a <code>while</code> loop or
65 * a <code>do-while</code> loop. If <code>true</code>, the
66 * condition is evaluated at the end of the loop, after the
67 * <code>Closure</code> is executed (thus guaranteeing that
68 * the <code>Closure</code> is executed at least once). If
69 * <code>false</code>, the condition is evaluated at the
70 * start of the loop, before the <code>Closure</code> is
71 * executed.
72 *
73 * @throws IllegalArgumentException Thrown if the <code>Predicate</code> or
74 * <code>Closure</code> is <code>null</code>.
75 */
76 public static <T> WhileClosure<T> decorate(Predicate<? super T> predicate, Closure<? super T> closure, boolean doLoop)
77 {
78 return new WhileClosure<T>(predicate, closure, doLoop);
79 }
80
81 /***
82 * Creates a new instance that decorates the specified <code>Closure</code>
83 * using the specified <code>Predicate</code> condition.
84 *
85 * @param predicate The <code>Predicate</code> used to determine when the
86 * loop should terminate.
87 * @param closure The <code>Closure</code> executed in the loop.
88 * @param doLoop Indicates whether to effect a <code>while</code> loop or
89 * a <code>do-while</code> loop. If <code>true</code>, the
90 * condition is evaluated at the end of the loop, after the
91 * <code>Closure</code> is executed (thus guaranteeing that
92 * the <code>Closure</code> is executed at least once). If
93 * <code>false</code>, the condition is evaluated at the
94 * start of the loop, before the <code>Closure</code> is
95 * executed.
96 *
97 * @throws IllegalArgumentException Thrown if the <code>Predicate</code> or
98 * <code>Closure</code> is <code>null</code>.
99 */
100 protected WhileClosure(Predicate<? super E> predicate, Closure<? super E> closure, boolean doLoop)
101 {
102 if (predicate == null) {
103 throw new IllegalArgumentException("Predicate must not be null");
104 }
105 if (closure == null) {
106 throw new IllegalArgumentException("Closure must not be null");
107 }
108 this.predicate = predicate;
109 this.closure = closure;
110 this.doLoop = doLoop;
111 }
112
113 /***
114 * Executes the <code>Closure</code> until the <code>Predicate</code>
115 * evaluates to <code>false</code>.
116 *
117 * @param input The input object to act upon.
118 */
119 public void execute(E input)
120 {
121 if (doLoop) {
122 closure.execute(input);
123 }
124 while (predicate.evaluate(input)) {
125 closure.execute(input);
126 }
127 }
128
129 /***
130 * Gets the <code>Predicate</code> that acts as the loop condition.
131 *
132 * @return The <code>Predicate</code> that acts as the loop condition.
133 *
134 * @since Collections15 1.0
135 */
136 public Predicate<? super E> getPredicate()
137 {
138 return predicate;
139 }
140
141 /***
142 * Gets the decorated <code>Closure</code>.
143 *
144 * @return The decorated <code>Closure</code>.
145 *
146 * @since Collections15 1.0
147 */
148 public Closure<? super E> getClosure()
149 {
150 return closure;
151 }
152
153 /***
154 * Indicates whether or not the loop is a <code>do-while</code> loop or a
155 * <code>while</code> loop.
156 *
157 * @return <code>true</code> if the loop is a <code>do-while</code> loop;
158 * <code>false</code> if it's a <code>while</code> loop.
159 *
160 * @since Collections15 1.0
161 */
162 public boolean isDoLoop()
163 {
164 return doLoop;
165 }
166
167 }