Skip to content

Instantly share code, notes, and snippets.

@stuart-marks
Created April 11, 2018 21:28
Show Gist options
  • Save stuart-marks/6acc8aa38c986422e561d6cadfef962b to your computer and use it in GitHub Desktop.
Save stuart-marks/6acc8aa38c986422e561d6cadfef962b to your computer and use it in GitHub Desktop.
Utilities for streams flatmapping from collections, arrays, and optionals.
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
// Suppose we have an API where:
// - a Clazz has a List of Methods,
// - a Method has a List of Parameters,
// - a Parameter has an array of Annotations, and
// - an Annotation has an Optional<Value>
// What's the best way to get all the values?
public class FlatMapping {
// Using lambda to convert each container into a Stream.
static void orig1(Clazz clazz, Consumer<Value> converter) {
clazz.getMethods().stream()
.flatMap(method -> method.getParameters().stream())
.flatMap(parameter -> Arrays.stream(parameter.getAnnotationsArray()))
.flatMap(annotation -> annotation.getOptionalValue().stream())
.forEach(converter);
}
// Using method references and extra flatmapping stream operations.
static void orig2(Clazz clazz, Consumer<Value> converter) {
clazz.getMethods().stream()
.map(Method::getParameters)
.flatMap(Collection::stream)
.map(Parameter::getAnnotationsArray)
.flatMap(Arrays::stream)
.map(Annotation::getOptionalValue)
.flatMap(Optional::stream)
.forEach(converter);
}
// Adapter functions from Collection, array, and Optional to Stream.
@SuppressWarnings("unchecked")
static <T,R> Function<T, Stream<R>> coll(Function<? super T, Collection<? extends R>> f) {
return t -> (Stream<R>) f.apply(t).stream();
}
static <T,R> Function<T, Stream<R>> arr(Function<? super T, R[]> f) {
return t -> Arrays.stream(f.apply(t));
}
@SuppressWarnings("unchecked")
static <T,R> Function<T, Stream<R>> opt(Function<? super T, Optional<? extends R>> f) {
return t -> (Stream<R>) f.apply(t).stream();
}
// Using adapter functions.
static void modified(Clazz clazz, Consumer<Value> converter) {
clazz.getMethods().stream()
.flatMap(coll(Method::getParameters))
.flatMap(arr(Parameter::getAnnotationsArray))
.flatMap(opt(Annotation::getOptionalValue))
.forEach(converter);
}
// ----- Stubs -----
class Clazz {
List<Method> getMethods() { return List.of(); }
}
class Method {
List<Parameter> getParameters() { return List.of(); }
}
class Parameter {
Annotation[] getAnnotationsArray() { return new Annotation[0]; }
List<Annotation> getAnnotations() { return List.of(); }
}
class Annotation {
Optional<Value> getOptionalValue() { return Optional.empty(); }
}
class Value { }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment