为什么我们要声明logging器静态最终?

在Java中,为什么最好的做法是声明一个logging器static final

 private static final Logger S_LOGGER 
  • private – 这样别的class级就不能劫持你的logging器
  • static – 所以每个类只有一个logging器实例,也避免了序列化logging器的企图
  • final – 无需在课堂上更改logging器

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

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

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

而不是:

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

前一种方式允许您在整个inheritance层次结构中的所有类中使用相同的logging器名称(实际类的名称)。 所以如果Bar延伸Foo ,两者都会login到Barlogging器。 有些人觉得更直观。

检查这个博客文章: 摆脱Java静态logging器 。 这是你如何使用jcabi-log使用slf4j:

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

不要再使用那个静电噪音了。

static意味着您只能为每个类创build一个logging器,而不是每个类的实例一个logging器。 一般来说,这就是你想要的 – 因为伐木工往往只根据class级而变化。

final意味着你不会改变loggervariables的值。 这是真的,因为你几乎总是把所有的日志消息(从一个类)扔到同一个logging器。 即使在极less数情况下,类可能要发送一些消息到不同的widgetDetailLoggerlogging器,创build另一个widgetDetailLoggerlogging器variables(例如widgetDetailLogger ),而不是通过dynamic地改变静态variables的值会更清楚。

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

对于一个logging器,(我假设你谈论Log4Jlogging器类),你想要一个类别的类别。 这应该导致只分配一次的事实,并且每个类不需要多于一个实例。 大概没有理由将一个类的Logger对象暴露给另一个类,那么为什么不把它变成私有的,并遵循OO原则。

你也应该注意,编译器能够从中受益。 所以你的代码执行更好一点:)

你什么时候想改变字段的值?

如果你永远不会改变这个价值,那么让这个领域的最终决定很明显 ,你永远不会改变价值。

因为这通常是可以在对象的所有实例中共享的那种function。 对于同一个类的两个实例,有一个不同的logging器是没有什么意义的(90%的时间)。

然而,你也可以看到有时logging器类声明为单例,甚至只是提供静态函数来logging你的东西。

这个代码是脆弱的,但是,在Java7之后,我们可以使用Logger lgr = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); 而不是静态logging器。

通常你使用类名来初始化logging器,这意味着如果它们不是静态的,那么最终每个类的实例都有一个实例(内存占用大),但是所有这些logging器都会共享相同的configuration和行为完全一样。 这就是static位的原因。 另外,因为每个Logger都是用类名初始化的,所以为了防止与子类发生冲突,可以声明它是private所以它不能被inheritance。 final来自于你在执行期间通常不会改变Logger – 所以一旦初始化,你永远不会“重新configuration”它 – 在这种情况下,确保没有人能够改变它是有道理的(错误或其他)。 当然,如果你打算以不同的方式使用Logger ,你可能不需要使用static final – 但我敢说,猜测80%的应用程序将使用日志logging,如上所述。

在大多数情况下,你将要改变的价值和final修饰符标记它。 每个类实例不需要单独的实例 – 所以是static首先,这是为了性能 – 它可以很好地优化(最终),并保存内存(静态)。

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

 ... public Logger logger = LoggerFactory.getLogger(DataSummary.class); public String toJson() { GsonBuilder gsonBuilder = new GsonBuilder(); return gsonBuilder.create().toJsonTree(this).toString(); } ... 

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

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