15

When a Java method accepts a Function<? super T, ? extends U>, then it's possible to provide method references in a syntax like the following: MyClass::myMethod.

However, I'm wondering if there's a way to chain multiple method calls. Here's an example to illustrate the case.

// on a specific object, without lambda
myString.trim().toUpperCase()

I am wondering if there is a syntax to translate this to a lambda expression. I am hoping there is something like the following:

// something like: (which doesn't work)
String::trim::toUpperCase

Alternatively, is there a utility class to merge functions?

// example: (which does not exist)
FunctionUtil.chain(String::trim, String::toUpperCase);
11
  • 2
    The canonical solution is to stop using method references, and just write myString -> myString.trim().toUpperCase(). Commented Sep 9, 2015 at 21:32
  • 3
    To be honest, all the available "syntactically sweet" options are actually uglier, frankly. Storing the lambdas in variables, writing a special static method, etc. are all more of a pain than just doing the straightforward thing. Commented Sep 9, 2015 at 21:43
  • 2
    Well it's kind of like 'function pointer' in C. So that we can refer to a function by its name. It makes no sense to "chain" that operation. Dot(.) are not chained, they are nested - a.f().g() == (a.f()).g(). We can nest :: too:) Commented Sep 9, 2015 at 22:16
  • 1
    @bvdb: You can combine the :: operator. Since x::y is an expression, the form (x::y)::z denote the form expression::name. Unfortunately, the left-hand side has no type, so it doesn’t work, but if it had a type, it was a function type as the expression x::y produces a function. Thus, z would be searched within the function type which is not what you want as you want to have z be searched within the result type. But there is no point in changing the way expression nesting works, as there is already a way to denote what you want: x->y().z(). Commented Sep 10, 2015 at 9:29
  • 1
    You can cast it to any single-abstract-method interface, but as said, that would imply searching the second method within that interface, not within the return type. So ((Function)x::y)::apply would be valid, but not useful. It does not create a function chain. It would be useful if Function had a static method, say chain, accepting two Functions so that you could write Function.chain(x::y, r::z) whereas r is the result type of y(). However, it’s still no advantage over x->x.y().z() Commented Sep 10, 2015 at 14:04

1 Answer 1

9

Java 8 Functions can be chained with the method andThen:

UnaryOperator<String> trimFunction = String::trim;
UnaryOperator<String> toUpperCaseFunction = String::toUpperCase;
Stream.of(" a ", " b ").map(trimFunction.andThen(toUpperCaseFunction)) // Stream is now ["A", "B"]

Note that in your actual example, String::trim does not compile because the trim method does not take any input, so it does not conform to the functional interface Function (same goes for String::toUpperCase).

Sign up to request clarification or add additional context in comments.

3 Comments

an instance method with N args is kind of a function with N+1 args; the extra arg is this. Therefore we can do UnaryOperator<String> trimFunc=String::trim
@bayou.io I didn't know you could do this. I edited my post with your proposition.
it conforms to Function<String,String> too...

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.