Reputation: 21
Let say, I have the following elements:
class A {
String s;
String getS() {return s;}
static boolean aFilter(String in) {return true or false}
static A aTransformation(A a) {return another A}
}
I would like to do the following with Java stream:
List<A> myAs = provideTheList();
myAs.stream()
.map(A::getS)
.filter(A::aFilter)
.map("back to stream of A")
.map(A::aTransformation)
.toList();
I know I can do it this way:
myAs.stream()
.filter(a -> A.aFilter(a.getS()))
.map(A::aTransformation)
.toList();
But it breaks, the expression of code as a series of transformations. I want to avoid the "a -> ...". I could write a function to do the "A.aFilter(a.getS())", but the above pattern is quite common and it's cumbersome to write additional function just for this. Something like:
myAs.stream()
.filter(A::aFilter ° A::getS) // function composition
...
would be perfect, but I don't know if we can express function composition in Java.
In Java we have predicates which are composable with and, or.
I do not found a way to compose functions in stream.
Another way would be to do the "back to stream of A", I do not believe it is possible to retrieve data at "another point of the stream".
Have you an elegant way to do the operation described above ?
Upvotes: 1
Views: 96
Reputation: 425278
Add a method to A:
public boolean passes() {
return aFilter(getS());
}
Then
myAs.stream()
.map(A::passes)
.map(A::aTransformation)
.toList();
Upvotes: 0
Reputation: 20544
You can create it yourself
static <T, U> Predicate<T> combine(Function<T, U> f, Predicate<U> p) {
return (T t) -> p.test(f.apply(t));
}
And use it as
Stream.of(X.builder().build())
.filter(combine(X::getS, String::isBlank))
.toList();
PS: You can do stuff like this
Stream.of(X.builder().build())
.filter(predicate(
For.<X>type()
.f(X::getS)
.andThen(Object::toString)
.andThen(String::isBlank)))
.toList();
If you put little more effort in utilities you creating. Here is code:
public class For<U> {
private static For INSTANCE = new For();
public static <U> For<U> type() { return INSTANCE; }
public static <T> Predicate<T> predicate(Function<T, Boolean> f) {
return f::apply;
}
public <R> Function<U, R> f(Function<U, R> f) { return f; }
}
EDIT If you restricted by using pure JDK try this:
Stream.of(
X.builder().build()
).filter(Function
.<X>identity()
.andThen(X::getS)
.andThen(Object::toString)
.andThen(String::isBlank)
::apply
).toList();
Upvotes: 1