Looking for java Keywords? Try Ask4Keywords

Java Language Регистрация сложных сообщений (эффективно)


пример

Давайте рассмотрим пример регистрации, который вы можете увидеть во многих программах:

public class LoggingComplex {
    
    private static final Logger logger = 
        Logger.getLogger(LoggingComplex.class.getName());

    private int total = 50, orders = 20;
    private String username = "Bob";

    public void takeOrder() {
        // (...) making some stuff
        logger.fine(String.format("User %s ordered %d things (%d in total)", 
                                  username, orders, total));
        // (...) some other stuff
    }

    // some other methods and calculations
}

Вышеприведенный пример выглядит отлично, но многие программисты забывают, что Java VM является стековой машиной. Это означает, что все параметры метода вычисляются перед выполнением метода.

Этот факт имеет решающее значение для ведения журнала на Java, особенно для регистрации чего-то на низких уровнях, таких как FINE , FINER , FINEST которые по умолчанию отключены. Давайте рассмотрим байт-код Java для takeOrder() .

Результат для javap -c LoggingComplex.class выглядит примерно так:

public void takeOrder();
    Code:
       0: getstatic     #27 // Field logger:Ljava/util/logging/Logger;
       3: ldc           #45 // String User %s ordered %d things (%d in total)
       5: iconst_3
       6: anewarray     #3  // class java/lang/Object
       9: dup
      10: iconst_0
      11: aload_0
      12: getfield      #40 // Field username:Ljava/lang/String;
      15: aastore
      16: dup
      17: iconst_1
      18: aload_0
      19: getfield      #36 // Field orders:I
      22: invokestatic  #47 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      25: aastore
      26: dup
      27: iconst_2
      28: aload_0
      29: getfield      #34 // Field total:I
      32: invokestatic  #47 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      35: aastore
      36: invokestatic  #53 // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
      39: invokevirtual #59 // Method java/util/logging/Logger.fine:(Ljava/lang/String;)V
      42: return

В строке 39 выполняется фактическое ведение журнала. Вся предыдущая работа (загрузка переменных, создание новых объектов, объединение строк в format ) может быть зря, если уровень ведения журнала установлен выше, чем FINE (и по умолчанию он есть). Такое ведение журнала может быть очень неэффективным, потребляя ненужные ресурсы памяти и процессора.

Вот почему вы должны спросить, включен ли уровень, который вы хотите использовать.

Правильный путь должен быть:

public void takeOrder() {
    // making some stuff
    if (logger.isLoggable(Level.FINE)) {
        // no action taken when there's no need for it
        logger.fine(String.format("User %s ordered %d things (%d in total)",
                                  username, orders, total));
    }
    // some other stuff
}

Поскольку Java 8:

Класс Logger имеет дополнительные методы, которые используют параметр Supplier<String> , который может быть просто предоставлен лямбдой:

public void takeOrder() {
    // making some stuff
    logger.fine(() -> String.format("User %s ordered %d things (%d in total)",
            username, orders, total));
    // some other stuff
}

Метод get() поставщиков get() в этом случае лямбда - вызывается только тогда, когда соответствующий уровень включен, и поэтому конструкция if больше не нужна.