In C#, a common optimization for methods that use delegates is to provide an overloaded method with an additional argument that lets you eliminate free variables from the lambda.
For example:
System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue>
{
public TValue GetOrAdd (TKey key, Func<TKey,TValue> valueFactory);
public TValue GetOrAdd<TArg> (TKey key, Func<TKey,TArg,TValue> valueFactory, TArg factoryArgument);
}
The "factoryArgument" in the second overload lets you use a static delegate for valueFactory instead of a closure, eliminating the need to allocate a new object each time the method is called with new arguments.
Java also has lambda expressions. However, the method for translating them into MethodHandles is different than C#. From what I've read, since the transformation is deferred until execution, Java can transparently eliminate free variables for capturing lambdas. Thus, whether or not calling a lambda expression allocates a new object is runtime-dependent.
If I'm designing a Java API that uses lambdas, would it still be worthwhile to provide overloaded methods similar to C#?
e.g.
interface Foo<T>
{
public T get(Supplier<? extends T> supp);
public <A> T get(Function<? super A, ? extends T> supp, A arg);
}
Or is it best to rely on the runtime to provide any optimizations and only include a single method?
e.g.
interface Foo<T>
{
public T get(Supplier<? extends T> supp);
}
To clarify my main question is: considering the differences in how the Java and C# runtimes translate closures, is providing an overload with manual lambda-lifting necessary in Java?