向所有Java专家致敬!
从Java8开始,我们可以在接口中使用默认实现(是的!)。 但是,如果要从默认方法进行记录,则会出现问题。
我有一种感觉,每当我想用默认方法记录某些内容时,调用.getLogger()是不明智的。
是的,可以在接口中定义静态变量 - 但这对接口来说不是一个好习惯+它暴露了记录器(必须是公共的)。
我现在的解决方案:
interface WithTimeout<Action> {
default void onTimeout(Action timedOutAction) {
LogHolder.LOGGER.info("Action {} time out ignored.", timedOutAction);
}
static final class LogHolder {
private static final Logger LOGGER = getLogger(WithTimeout.class);
}
}
对于每个人来说,LogHolder仍然是可见的,因为它没有提供任何方法,并且它应该是接口内部的。
你们有没有人知道更好的解决方案? :)
编辑:我使用Logback支持的SLF4J
答案 0 :(得分:11)
如果您不想将类LogHolder
公开给公众,请不要将其设为interface
的成员类。使它成为成员类没有任何好处,你甚至不保存输入,因为你必须使用持有者类的名称限定字段访问,无论它是成员类还是同一个包中的类:
public interface WithTimeout<Action> {
default void onTimeout(Action timedOutAction) {
LogHolder.LOGGER.info("Action {} time out ignored.", timedOutAction);
}
}
final class LogHolder { // not public
static final Logger LOGGER = getLogger(WithTimeout.class);
}
答案 1 :(得分:0)
你走了。
Logger是私有接口。除此接口及其默认方法之外,没有人可以访问Test2中的任何内容。没有什么可以扩展Test2类。
没有人建议你这样做......但它有效! 这是一种很好的方式来访问主界面的类记录器,并且可能是一种聪明的方式来做其他不完全疯狂的事情。
这与OP问题中的LogHolder非常相似,除了Test2类都是私有方法和构造函数私有,并且类没有标记为static。
作为一个额外的奖励,它保持状态,静态和每个实例。 (请不要在真实的节目中这样做!)
public class TestRunner { public static void main(String[] args) { Test test = new Test() { }; test.sayHello("Jane"); System.out.println("Again"); test.sayHello("Bob"); } } public interface Test { default void sayHello(String name) { Logger log = Test2.log; Test2 ref = Test2.getMine.apply(this); int times = ref.getTimes(); for (int i = 0; i < times; i++) { System.out.println(i + ": Hello " + name); } log.info("just said hello {} times :)",times); } final class Test2 { private static final Logger log = LoggerFactory.getLogger(Test.class); private static final Map lookup = new WeakHashMap(); private static final Function getMine = (obj) -> { return lookup.computeIfAbsent(obj, (it) -> new Test2()); }; private int calls = 0; private Test2() { } private void setCalls(int calls) { this.calls = calls; } private int getCalls() {return calls;} private int getTimes() {return ++calls;} } }