forked from kangjianwei/LearningJDK
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Optional.java
535 lines (484 loc) · 20.8 KB
/
Optional.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
/*
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.util;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
/**
* A container object which may or may not contain a non-{@code null} value.
* If a value is present, {@code isPresent()} returns {@code true}. If no
* value is present, the object is considered <i>empty</i> and
* {@code isPresent()} returns {@code false}.
*
* <p>Additional methods that depend on the presence or absence of a contained
* value are provided, such as {@link #orElse(Object) orElse()}
* (returns a default value if no value is present) and
* {@link #ifPresent(Consumer) ifPresent()} (performs an
* action if a value is present).
*
* <p>This is a <a href="../lang/doc-files/ValueBased.html">value-based</a>
* class; use of identity-sensitive operations (including reference equality
* ({@code ==}), identity hash code, or synchronization) on instances of
* {@code Optional} may have unpredictable results and should be avoided.
*
* @param <T> the type of value
*
* @apiNote {@code Optional} is primarily intended for use as a method return type where
* there is a clear need to represent "no result," and where using {@code null}
* is likely to cause errors. A variable whose type is {@code Optional} should
* never itself be {@code null}; it should always point to an {@code Optional}
* instance.
* @since 1.8
*/
/*
* 单元素容器(引用类型版本)
*
* 通常用于在流的终端阶段收集完数据后进行一些收尾工作。
* 当然,还可以用在一些非空判断中,用于简化非空判断的逻辑以及将非空判断与其他逻辑进行整合。
*/
public final class Optional<T> {
/**
* Common instance for {@code empty()}.
*/
private static final Optional<?> EMPTY = new Optional<>();
/**
* If non-null, the value; if null, indicates no value is present
*/
private final T value; // 封装的元素
/*▼ 构造器 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Constructs an empty instance.
*
* @implNote Generally only one empty instance, {@link Optional#EMPTY},
* should exist per VM.
*/
private Optional() {
this.value = null;
}
/**
* Constructs an instance with the described value.
*
* @param value the non-{@code null} value to describe
*
* @throws NullPointerException if value is {@code null}
*/
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
/*▲ 构造器 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 静态工厂,创建Optional ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Returns an empty {@code Optional} instance. No value is present for this
* {@code Optional}.
*
* @param <T> The type of the non-existent value
*
* @return an empty {@code Optional}
*
* @apiNote Though it may be tempting to do so, avoid testing if an object is empty
* by comparing with {@code ==} against instances returned by
* {@code Optional.empty()}. There is no guarantee that it is a singleton.
* Instead, use {@link #isPresent()}.
*/
public static <T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
/**
* Returns an {@code Optional} describing the given non-{@code null}
* value.
*
* @param value the value to describe, which must be non-{@code null}
* @param <T> the type of the value
*
* @return an {@code Optional} with the value present
*
* @throws NullPointerException if value is {@code null}
*/
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
/**
* Returns an {@code Optional} describing the given value, if
* non-{@code null}, otherwise returns an empty {@code Optional}.
*
* @param value the possibly-{@code null} value to describe
* @param <T> the type of the value
*
* @return an {@code Optional} with a present value if the specified value
* is non-{@code null}, otherwise an empty {@code Optional}
*/
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
/*▲ 静态工厂,创建Optional ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 获取元素 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* If a value is present, returns the value, otherwise throws
* {@code NoSuchElementException}.
*
* @return the non-{@code null} value described by this {@code Optional}
*
* @throws NoSuchElementException if no value is present
* @apiNote The preferred alternative to this method is {@link #orElseThrow()}.
*/
// 获取Optional中元素(如果没有元素将抛出异常)
public T get() {
if(value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
/**
* If a value is present, returns an {@code Optional} describing the value,
* otherwise returns an {@code Optional} produced by the supplying function.
*
* @param supplier the supplying function that produces an {@code Optional}
* to be returned
*
* @return returns an {@code Optional} describing the value of this
* {@code Optional}, if a value is present, otherwise an
* {@code Optional} produced by the supplying function.
*
* @throws NullPointerException if the supplying function is {@code null} or
* produces a {@code null} result
* @since 9
*/
// 如果元素存在,则返回Optional。否则,从supplier中获取元素。
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
Objects.requireNonNull(supplier);
if(isPresent()) {
return this;
} else {
@SuppressWarnings("unchecked")
Optional<T> r = (Optional<T>) supplier.get();
return Objects.requireNonNull(r);
}
}
/**
* If a value is present, returns the value, otherwise returns
* {@code other}.
*
* @param other the value to be returned, if no value is present.
* May be {@code null}.
*
* @return the value, if present, otherwise {@code other}
*/
// 如果元素存在,返回它。否则,返回other
public T orElse(T other) {
return value != null ? value : other;
}
/**
* If a value is present, returns the value, otherwise returns the result
* produced by the supplying function.
*
* @param supplier the supplying function that produces a value to be returned
*
* @return the value, if present, otherwise the result produced by the
* supplying function
*
* @throws NullPointerException if no value is present and the supplying
* function is {@code null}
*/
// 如果元素存在,返回它。否则,从supplier中获取
public T orElseGet(Supplier<? extends T> supplier) {
return value != null ? value : supplier.get();
}
/**
* If a value is present, returns the value, otherwise throws
* {@code NoSuchElementException}.
*
* @return the non-{@code null} value described by this {@code Optional}
*
* @throws NoSuchElementException if no value is present
* @since 10
*/
// 如果元素存在,返回它。否则,抛出异常
public T orElseThrow() {
if(value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
/**
* If a value is present, returns the value, otherwise throws an exception
* produced by the exception supplying function.
*
* @param <X> Type of the exception to be thrown
* @param exceptionSupplier the supplying function that produces an
* exception to be thrown
*
* @return the value, if present
*
* @throws X if no value is present
* @throws NullPointerException if no value is present and the exception
* supplying function is {@code null}
* @apiNote A method reference to the exception constructor with an empty argument
* list can be used as the supplier. For example,
* {@code IllegalStateException::new}
*/
// 如果元素存在,返回它。否则,从exceptionSupplier中取出异常并抛出
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if(value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
/*▲ 获取元素 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 存在性判断 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* If a value is present, returns {@code true}, otherwise {@code false}.
*
* @return {@code true} if a value is present, otherwise {@code false}
*/
// 元素是否存在
public boolean isPresent() {
return value != null;
}
/**
* If a value is not present, returns {@code true}, otherwise
* {@code false}.
*
* @return {@code true} if a value is not present, otherwise {@code false}
*
* @since 11
*/
// 元素是否不存在
public boolean isEmpty() {
return value == null;
}
/**
* If a value is present, performs the given action with the value,
* otherwise does nothing.
*
* @param action the action to be performed, if a value is present
*
* @throws NullPointerException if value is present and the given action is
* {@code null}
*/
// 如果元素存在,执行action动作
public void ifPresent(Consumer<? super T> action) {
if(value != null) {
action.accept(value);
}
}
/**
* If a value is present, performs the given action with the value,
* otherwise performs the given empty-based action.
*
* @param action the action to be performed, if a value is present
* @param emptyAction the empty-based action to be performed, if no value is
* present
*
* @throws NullPointerException if a value is present and the given action
* is {@code null}, or no value is present and the given empty-based
* action is {@code null}.
* @since 9
*/
// 如果元素存在,执行actin动作。否则,执行emptyAction动作。
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
if(value != null) {
action.accept(value);
} else {
emptyAction.run();
}
}
/*▲ 存在性判断 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 流式操作 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* If a value is present, returns a sequential {@link Stream} containing
* only that value, otherwise returns an empty {@code Stream}.
*
* @return the optional value as a {@code Stream}
*
* @apiNote This method can be used to transform a {@code Stream} of optional
* elements to a {@code Stream} of present value elements:
* <pre>{@code
* Stream<Optional<T>> os = ..
* Stream<T> s = os.flatMap(Optional::stream)
* }</pre>
* @since 9
*/
// 创建单元素流
public Stream<T> stream() {
if(!isPresent()) {
return Stream.empty();
} else {
return Stream.of(value);
}
}
/**
* If a value is present, and the value matches the given predicate,
* returns an {@code Optional} describing the value, otherwise returns an
* empty {@code Optional}.
*
* @param predicate the predicate to apply to a value, if present
*
* @return an {@code Optional} describing the value of this
* {@code Optional}, if a value is present and the value matches the
* given predicate, otherwise an empty {@code Optional}
*
* @throws NullPointerException if the predicate is {@code null}
*/
// 过滤元素
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if(!isPresent()) {
return this;
} else {
return predicate.test(value) ? this : empty();
}
}
/**
* If a value is present, returns an {@code Optional} describing (as if by
* {@link #ofNullable}) the result of applying the given mapping function to
* the value, otherwise returns an empty {@code Optional}.
*
* <p>If the mapping function returns a {@code null} result then this method
* returns an empty {@code Optional}.
*
* @param mapper the mapping function to apply to a value, if present
* @param <U> The type of the value returned from the mapping function
*
* @return an {@code Optional} describing the result of applying a mapping
* function to the value of this {@code Optional}, if a value is
* present, otherwise an empty {@code Optional}
*
* @throws NullPointerException if the mapping function is {@code null}
* @apiNote This method supports post-processing on {@code Optional} values, without
* the need to explicitly check for a return status. For example, the
* following code traverses a stream of URIs, selects one that has not
* yet been processed, and creates a path from that URI, returning
* an {@code Optional<Path>}:
*
* <pre>{@code
* Optional<Path> p =
* uris.stream().filter(uri -> !isProcessedYet(uri))
* .findFirst()
* .map(Paths::get);
* }</pre>
*
* Here, {@code findFirst} returns an {@code Optional<URI>}, and then
* {@code map} returns an {@code Optional<Path>} for the desired
* URI if one exists.
*/
// 映射元素
public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if(!isPresent()) {
return empty();
} else {
return Optional.ofNullable(mapper.apply(value));
}
}
/**
* If a value is present, returns the result of applying the given
* {@code Optional}-bearing mapping function to the value, otherwise returns
* an empty {@code Optional}.
*
* <p>This method is similar to {@link #map(Function)}, but the mapping
* function is one whose result is already an {@code Optional}, and if
* invoked, {@code flatMap} does not wrap it within an additional
* {@code Optional}.
*
* @param <U> The type of value of the {@code Optional} returned by the
* mapping function
* @param mapper the mapping function to apply to a value, if present
*
* @return the result of applying an {@code Optional}-bearing mapping
* function to the value of this {@code Optional}, if a value is
* present, otherwise an empty {@code Optional}
*
* @throws NullPointerException if the mapping function is {@code null} or
* returns a {@code null} result
*/
// 对元素降维
public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
Objects.requireNonNull(mapper);
if(!isPresent()) {
return empty();
} else {
@SuppressWarnings("unchecked")
Optional<U> r = (Optional<U>) mapper.apply(value);
return Objects.requireNonNull(r);
}
}
/*▲ 流式操作 ████████████████████████████████████████████████████████████████████████████████┛ */
/**
* Indicates whether some other object is "equal to" this {@code Optional}.
* The other object is considered equal if:
* <ul>
* <li>it is also an {@code Optional} and;
* <li>both instances have no value present or;
* <li>the present values are "equal to" each other via {@code equals()}.
* </ul>
*
* @param obj an object to be tested for equality
*
* @return {@code true} if the other object is "equal to" this object
* otherwise {@code false}
*/
@Override
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if(!(obj instanceof Optional)) {
return false;
}
Optional<?> other = (Optional<?>) obj;
return Objects.equals(value, other.value);
}
/**
* Returns the hash code of the value, if present, otherwise {@code 0}
* (zero) if no value is present.
*
* @return hash code value of the present value or {@code 0} if no value is
* present
*/
@Override
public int hashCode() {
return Objects.hashCode(value);
}
/**
* Returns a non-empty string representation of this {@code Optional}
* suitable for debugging. The exact presentation format is unspecified and
* may vary between implementations and versions.
*
* @return the string representation of this instance
*
* @implSpec If a value is present the result must include its string representation
* in the result. Empty and present {@code Optional}s must be unambiguously
* differentiable.
*/
@Override
public String toString() {
return value != null ? String.format("Optional[%s]", value) : "Optional.empty";
}
}