-
Notifications
You must be signed in to change notification settings - Fork 2
Towards Declarative Programming
Predicate
: takes an argument and returns a boolean
.
Function
: argument and return types differ.
Supplier
: takes no argument and returns a value.
Consumer
: takes an argument and returns nothing.
Interface | Function Signature | Example |
---|---|---|
Predicate<T> |
boolean test(T t) |
Collection::isEmpty |
Function<T,R> |
R apply(T t) |
Arrays::asList |
Supplier<T> |
T get() |
Math::random |
Consumer<T> |
void accept(T t) |
System.out::println |
There are three variants of each of the above interfaces to operate on the primitive types int
, long
and double
. Their names are derived from the basic interfaces by prefixing then with a primitive type.
Examples: IntPredicate
, LongFunction<int[]>
, DoubleSupplier
.
For use when the result type is primitive.
- If both the sources and result types are primitive, prefix
Function
with SrcToResult, for exampleLongToIntFunction
. - If the source is a primitive and the result is an object reference, prefix
Function
with <Src>ToObj, for exampleDoubleToObjFunction
.
BiPredicate<T,U>
, BiFunction<T,U,R>
, and BiConsumer<T,U>
.
-
There are also
BiFunction
variants returning the three relevant primitive types:ToIntBiFunction<T,U>
,ToLongBiFunction<T,U>
andToDoubleBiFunction<T,U>
. -
There are two-argument variants of Consumer that take one object reference and one primitive type:
ObjDoubleConsumer<T>
,ObjIntConsumer<T>
andObjLongConsumer<T>
.
BooleanSupplier
, a variant of Supplier
that returns boolean
values.
stream: a finite or infinite sequence of data elements
stream pipeline: a multistage computation on these elements
// Suppose we have an arbitrary list of words and we want to count all words that are longer than 10 characters long.
import java.util.List;
List<String> words; // assume declared
// classical iteration
int count = 0;
for (String w: words) {
if (w.length() > 10) {
count++;
}
}
// streams
long count = words.stream().filter(w -> w.length() > 12).count();
- A stream does not store its elements. They may be stored in an underlying collection or generated on demand.
- Stream operations don't mutate their source. For example, the
filter
method does not remove elemtns from a stream but yields a new stream in which they are not present. - Stream operations are lazy when possible. This means they are not exectuted until their result is needed. For example, if you only ask for the first five long words instead of all, the filter method will stop filtering after the fifth match. As a consequence, you can have infinite streams.
- Create a stream
- Specify intermediate operations for transforming the initial stream into others, possibly in multiple steps.
- Apply a terminal operation to produce a result. This operation forces the execution of the lazy operations that precede it. Afterwards, the stream can no longer be used.
The argument of filter
is a Predicate<T>
, a function from T
to boolean
.
map
is used to transform the values in a stream by passing the function that carries out the transformation. For example, you can transform all words to lowercase like this:
Stream<String> lowercaseWords = words.stream().map(String::toLowerCase);
When you use map, a function is applied to each element, and the result is a new stream with the results.
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
yields a stream obtained by concatenating the results of applying mapper
to the elements of this stream. (Note that each result is a stream.)
Optional<T>
represents an immutable container that can hold either a single non-null T
reference or nothing at all. An optional that contains nothing is said to be empty. A value is said to be present in an optional that is not empty. An optional is essentially an immutable collection that can hold at most one element.
Let's describe a method to calculate the maximum value in a collection, according to its elements' natural order.
public static <E extends Comparable<E>> E max(Collection<E> c) {
if (c.isEmpty()) {
throw new IllegalArgumentException("Empty Collection");
}
E result = null;
for (E e: c) {
if (result == null || e.compareTo(result) > 0) {
result = e;
}
}
return result;
}
// Using Optionals
import java.util.Optional;
public static <E extends Comparable<E>> Optional<E> max(Collection<E> c) {
if (c.isEmpty()) {
return Optional.empty();
}
E result = null;
for (E e: c) {
if (result == null || e.compareTo(result) > 0) {
result = e;
}
}
return Optional.of(result);
}
If a method returns an optional, the client gets to choose what action to take if the method can't return a value.
// You can provide a chosen default value
String lastWord = max(words).orElse("No words!");
// Throw a chosen exception
HighScore highScore = max(highscores).orElseThrow(new NoHighScoreException());
// Get the value from a nonempty optional
Element lastNobleGas = max(Elements.NOBLE_GASES).get();
java.util.Optional
return type | method | Description |
---|---|---|
T |
orElse(T other) |
yields the value of this Optional , or other if this Optional is empty. |
T |
orElseGet(Supplier<? extends T> other) |
yields the value of this Optional , or the result of invoking other if this Optional is empty. |
<X extends Throwable> T |
orElseThrow(Supplier<? extends X> exceptionSupplier) |
yields the value of this Optional , or throws the result of invoking exceptionSupplier if this Optional is empty. |
void |
ifPresent(Consumer<? super T> action) |
if this Optional is nonempty, passes its value to action . |
void |
ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) |
if this Optional is nonempty, passes its value to action, else invokes emptyAction . |
<U> Optional<U> |
map(Function<? super T,? extends U> mapper) |
yields an Optional whose value is obtained by applying the given function to the value of this Optional if present, or an empty Optional otherwise. |
Optional<T> |
filter(Predicate<? super T> predicate) |
yields an Optional with the value of this Optional if it fulfills the given predicate, or an empty Optional otherwise. |
Optional<T> |
or(Supplier<? extends Optional<? extends T>> supplier) |
yields this Optional if it is nonempty, or the one produced by the supplier otherwise. |
T |
get() |
|
T |
orElseThrow() |
yields the value of this Optional , or throws a NoSuchElementException if it is empty. |
boolean |
isPresent() |
returns true if this Optional is not empty. |
<T> Optional<T> |
of(T value) |
|
<T> Optional<T> |
ofNullable(T value) |
yields an Optional with the given value. If value is null , the first method throws a NullPointerException and the second method yields an empty Optional . |
<T> Optional<T> |
empty() |
yields an empty Optional . |
<U> Optional<U> |
flatMap(Function<? super T,? extends Optional<? extends U>> mapper) |
yields the result of applying mapper to the value in this Optional if present, or an empty optional otherwise. |
<U> Optional<U> |
flatMap(Function<? super T,Optional<U>> mapper) |
yields the result of applying mapper to the value of this Optional , or an empty Optional if this Optional is empty. |