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