If you’re programming in more advanced languages like Scala or Ceylon, or even JavaScript,
“nested functions” or
“local functions” are a very common idiom to you. For instance, you’ll write things like fibonacci functions as such:
def f() = {
def g() = "a string!"
g() + "– says g"
}
(
Question from Stack Overflow by Aaron Yodaiken)
The
f()
function contains a nested
g()
function, which is local to the scope of the outer
f()
function.
In Java, there is no way to create a local function like this, but you can assign a lambda expression to a local variable and use that instead.
The above example can be translated to the following Java code:
String f() {
Supplier<String> g = () -> "a string!";
return g.get() + "- says g";
}
While this example is rather trivial, a much more useful use-case is testing. For instance, consider the following
jOOλ unit test, which checks whether the
Stream.close()
semantics is properly implemented across all sorts of jOOλ
Seq
methods, that combine two streams into one:
@Test
public void testCloseCombineTwoSeqs() {
Consumer<BiFunction<Stream<Integer>, Stream<Integer>, Seq<?>>> test = f -> {
AtomicBoolean closed1 = new AtomicBoolean();
AtomicBoolean closed2 = new AtomicBoolean();
Stream s1 = Stream.of(1, 2).onClose(() -> closed1.set(true));
Stream s2 = Stream.of(3).onClose(() -> closed2.set(true));
try (Seq s3 = f.apply(s1, s2)) {
s3.collect(Collectors.toList());
}
assertTrue(closed1.get());
assertTrue(closed2.get());
};
test.accept((s1, s2) -> seq(s1).concat(s2));
test.accept((s1, s2) -> seq(s1).crossJoin(s2));
test.accept((s1, s2) -> seq(s1).innerJoin(s2, (a, b) -> true));
test.accept((s1, s2) -> seq(s1).leftOuterJoin(s2, (a, b) -> true));
test.accept((s1, s2) -> seq(s1).rightOuterJoin(s2, (a, b) -> true));
}
The local function is
test
, and it takes two
Stream<Integer>
arguments, producing a
Seq<?>
result.
Why not just write a private method?
Of course, this could have been solved with a private method as well, classic Java style. But sometimes, using a local scope is much more convenient, as the test
Consumer
(local function) does not escape the scope of this single unit test. It should be used only within this single method.
An alternative, more classic Java way would have been to define a local class, instead, and put the function inside of that. But this solution is much more lean.
One disadvantage, however, is that recursion is much harder to implement this way, in Java. See also:
https://stackoverflow.com/q/19429667/521799Like this:
Like Loading...
Published by lukaseder
I made jOOQ
View all posts by lukaseder