从默认接口方法记录

时间:2015-02-25 13:56:11

标签: java interface java-8

向所有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

2 个答案:

答案 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;}
    }
}