为什么我们声明Loggers静态最终?

时间:2011-07-11 16:45:03

标签: java logging

在Java中,为什么最佳做法是声明记录器static final

private static final Logger S_LOGGER

15 个答案:

答案 0 :(得分:190)

  • private - 这样任何其他类都无法劫持您的记录器
  • static - 所以每个类只有一个记录器实例,也避免尝试序列化记录器
  • final - 无需在课程的整个生命周期内更改记录器

另外,我更喜欢名称log尽可能简单,但更具描述性。

编辑:但是这些规则有一个有趣的例外:

protected final Logger log = LoggerFactory.getLogger(getClass());

而不是:

private static final Logger log = LoggerFactory.getLogger(Foo.class);

前一种方法允许您在整个继承层次结构中的所有类中使用相同的记录器名称(实际类的名称)。因此,如果Bar扩展Foo,则两者都会记录到Bar记录器。有些人觉得它更直观。

答案 1 :(得分:11)

查看此博文:Get Rid of Java Static Loggers。这就是你如何将slf4j用于jcabi-log

import com.jcabi.log.Logger;
class Foo {
  void save(File f) {
    Logger.info(this, "file %s saved successfully", f);
  }
}

再也不要使用静电噪音了。

答案 2 :(得分:4)

static 表示您只为每个类创建一个Logger,而不是每个类的实例创建一个记录器。一般来说,这就是你想要的 - 因为记录器往往只是根据类别而变化。

final 表示您不会更改logger变量的值。这是真的,因为您几乎总是将所有日志消息(从一个类)抛出到同一个记录器。即使在一个类可能想要将一些消息发送到另一个记录器的极少数情况下,创建另一个记录器变量(例如widgetDetailLogger)而不是通过动态改变静态变量的值也会更加清晰。

答案 3 :(得分:3)

您希望何时更改字段的值?

如果您永远不会更改该值,那么将该字段设为最终会使显而易见您永远不会更改该值。

答案 4 :(得分:3)

通常你使用类名初始化记录器来记录 - 这意味着如果它们不是静态的,你最终会得到类的每个实例都有一个实例(高内存占用),但所有的这些记录器将共享相同的配置并且行为完全相同。这就是static位背后的原因。另外,因为每个Logger都是使用类名初始化的,为了防止与子类发生冲突,您将其声明为private,以便不能继承它。 final来自于您在执行期间通常不会更改Logger的点 - 因此,一旦初始化,您永远不会“重新配置”它 - 在这种情况下,制作它是有意义的最终确保没有人可以改变它(错误或其他)。 当然,如果你打算以不同的方式使用Logger,你可能需要来使用static final - 但我敢冒昧地猜测80%的应用会使用记录如上所述。

答案 5 :(得分:3)

要回答这个问题,你应该问自己“静态”和“最终”是什么。

对于Logger,(我假设你讲的是Log4J Logger类)你想要每个类一个类别。这应该导致您只分配一次,并且每个类不需要多个实例。并且可能没有理由将一个类的Logger对象暴露给另一个类,所以为什么不将它变为私有并遵循一些OO-Principles。

另外你应该注意,编译器能够从中受益。所以你的代码表现得更好一些:)

答案 6 :(得分:2)

因为这通常是可以在对象的所有实例中共享的功能。对同一类的两个实例使用不同的记录器没有多大意义(90%的时间)。

但是,您有时也会看到声明为单身的记录器类,甚至只是提供静态函数来记录您的东西。

答案 7 :(得分:2)

在大多数情况下,您不会更改引用,final修饰符会将其标记出来。每个类实例不需要单独的实例 - 所以static首先是性能 - 它可以很好地优化(最终)并节省内存(静态)。

答案 8 :(得分:2)

此代码容易受到攻击,但在Java7之后,我们可以使用Logger lgr = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); 代替静态记录器。

答案 9 :(得分:1)

理想情况下,直到Java 7,Logger都应如下所示,以便不给出声纳并给出顺应代码: 私人:永远不能在其父类之外访问。如果另一个类需要记录某些内容,则应实例化其自己的记录器。 静态:不依赖于类(对象)的实例。在记录某些内容时,当然可以在消息中提供上下文信息,但是应该在类级别创建记录器,以防止与每个对象一起创建记录器,从而防止占用大量内存。 最终:每个课程只能创建一次。

答案 10 :(得分:1)

根据我从互联网上获得的有关使记录器静态或不静态的信息,最佳实践是根据用例使用它。

有两个主要参数:

1)使其静态时,不会对其进行垃圾回收(内存使用和性能)。

2)当您不将其设置为静态时,将为每个类实例(内存使用情况)创建它

因此,当您为单例创建记录器时,无需将其设置为静态。因为只有一个实例,所以只有一个记录器。

另一方面,如果要为模型或实体类创建记录器,则应将其设置为静态,以免创建重复的记录器。

答案 11 :(得分:0)

除了在其他答案中给出的理由之外,我遇到的一件事是,如果我的记录器既不是静态的也不是最终的:

...
public Logger logger = LoggerFactory.getLogger(DataSummary.class);

public String toJson() {
  GsonBuilder gsonBuilder = new GsonBuilder();   
  return gsonBuilder.create().toJsonTree(this).toString();
}
...

在某些情况下(当我使用Gson库时)我会得到stackoverflow异常。我的具体情况是实例化包含非静态非最终记录器的类。然后调用调用GsonBuilder的toJson方法:

...
DataSummary ds = new DataSummary(data);    
System.out.println(ds.toJson());
...

答案 12 :(得分:0)

实际上,静态记录器可能“有害”,因为它们应该在静态上下文中工作。具有动态环境时OSGi可能有助于使用非静态记录器。由于某些日志记录实现会在内部缓存记录器(AFAIK至少为log4j),因此对性能的影响可以忽略不计。

静态记录器的一个缺点是例如。垃圾回收(当一个类仅使用一次时,例如,在初始化期间,记录器仍会保留)。

有关更多详细信息,请检查:

另请参阅:

答案 13 :(得分:0)

我们使用

private - 这样它仍然是类的私有数据成员(我们通常希望每个类级别变量都使用它)。

静态 - 这很重要。我们想要整个类的单个记录器实例,而不是该类的每个新实例/对象都会产生一个新的记录器。 java中的静态关键字也是为此而生的。因此我们声明它是静态的

final - 我们不想更改 logger 变量的值,而是希望它在整个类生命周期中保持不变。

答案 14 :(得分:-1)

对于内部静态类,您仍然需要静态记录器