Logging API
Adam Hawthorne
adam.hawthorne at gmail.com
Tue May 22 13:38:09 PDT 2012
On Tue, May 22, 2012 at 4:17 PM, Brian Goetz <brian.goetz at oracle.com> wrote:
> Yes, some time ago we ran a "point lambdafication" survey on this list,
> and this was the #1 suggestion. So rest assured, it is on the list of
> ideas.
>
Thanks for the reassurance.
>
> I'd also note that the primary goal of such a change is performance, and
> the story there isn't as perfect as you might prefer. Capturing a lambda
> which captures variables from the enclosing scope has a cost, comparable to
> an object allocation. (On the other hand, capturing non-capturing lambdas,
> which will be the common case for many filter/map/reduce type of
> operations, should be basically free.) So while you defer creating the
> string until you need it, you do not necessarily defer creating the lambda
> (though the VM may be able to optimize that away in some cases.) So the
> "Factory<String> approach" will be faster than just precomputing the string
> unconditionally, but probably slower than the commonly used trick of
> preceding the logging call with an "if (logger.level() >= DEBUG)"
> statement. So if you were thinking this would be a totally free way to
> replace those ugly if statements, you might be disappointed.
>
The log(Level, String, Object) method in the Oracle JDK does as its first
statement:
if (level.intValue() < levelValue || levelValue == offValue) {
return;
}
I think Hotspot is currently able to inline that method. It also seems
like allocating a lambda should be side-effect free. If so, might we
expect the VM to be smart enough in JDK 8 to know that it can push the
allocation inside that 'if' (assuming it's not used for anything else)?
Adam
> Of course, there's lots the VM might do to help in the future. But that's
> the future.
>
>
>
> On 5/22/2012 4:01 PM, Adam Hawthorne wrote:
>
>> I don't know if it's premature to discuss non-Collections APIs, but in
>> trying out Lambda, I encountered problems using java.util.logging.Logger.
>> Here's some sample code:
>>
>>
>> import static java.util.logging.Level.INFO;
>> import static LambdaTest.Stringifier._;
>>
>> import java.util.concurrent.Callable;
>> import java.util.logging.Logger;
>>
>> public class LambdaTest {
>> public static void main(String... argv) {
>> // Fails to compile, no suitable method
>> // Logger.getAnonymousLogger().**log(INFO, "Hello {0}", () ->
>> "World");
>>
>> // Fails to compile, java.lang.Object method restrictions
>> // ToString arg1 = () -> "World";
>> // Logger.getAnonymousLogger().**log(INFO, "Hello {0}", arg1);
>>
>> // Does not produce "hoped for" output, Callable<String>.get()
>> isn't the same as toString()
>> Callable<String> arg2 = () -> "World";
>> Logger.getAnonymousLogger().**log(INFO, "Hello {0}", arg2);
>>
>> // Does not produce "hoped for" output, Object.toString() is
>> defined.
>> Stringer arg3 = () -> "World";
>> Logger.getAnonymousLogger().**log(INFO, "Hello {0}", arg3);
>>
>> // Works, but hokey/extra allocation
>> Logger.getAnonymousLogger().**log(INFO, "Hello {0}", _(() ->
>> "World"));
>> }
>>
>> public interface ToString {
>> String toString();
>> }
>>
>> public interface Stringer {
>> String string();
>>
>> String toString() default {
>> return string();
>> }
>> }
>>
>> public static class Stringifier {
>> private final Callable<String> val;
>>
>> public Stringifier(Callable<String> val) {
>> this.val = val;
>> }
>>
>> @Override
>> public String toString() {
>> try {
>> return val.call();
>> } catch (Exception e) {
>> throw new RuntimeException(e);
>> }
>> }
>>
>> public static Stringifier _(Callable<String> val) {
>> return new Stringifier(val);
>> }
>> }
>> }
>>
>> One of the nice things about the logging API is that it doesn't actually
>> invoke toString() on the arguments unless the log level is actually
>> enabled. Lambdas are obvious choices for this kind of delayed execution,
>> but I tried to do battle against Logging and I lost.
>>
>> It seems to me that option 4 should work, although I understand from
>> Defenders section 3, Object.toString() takes precedence over the defender
>> toString() in Stringer. It would be helpful if using the Logging API was
>> more friendly towards Lambdas.
>>
>> Adam
>>
>>
--
"... that I may know Him and the power of His resurrection, and the
fellowship of His sufferings, being conformed to His death, if, by any
means, I may attain to the resurrection from the dead."
More information about the lambda-dev
mailing list