代码之家  ›  专栏  ›  技术社区  ›  John

在Java中有没有用Java方法引用重写方法的缩写?

  •  3
  • John  · 技术社区  · 6 年前

    我经常遇到这样的情况

    component.addWindowListener() { new WindowListener() {
            // quick overriding to make syntax less verbose
            windowClosing(e) -> Foo::doFoo;
    
            windowActivated(e) -> Foo::doFoo;
        }
    }
    

    目前主要是这样的:

    component.addWindowListener() new WindowListener() {
        @Override
        public void windowClosing(WindowEvent e) {
            Foo.doFoo(e);
        }
    
        @Override
        public void windowActivated(WindowEvent e) {
            Foo.doFoo(e);
        }
    }
    

    当方法引用指向某个函数时:

    public static void doFoo(WindowEvent e) {
        // does code
    }
    

    这样的事可能吗?因为对非功能接口的重写是相当令人沮丧的。

    4 回复  |  直到 6 年前
        1
  •  3
  •   Holger    6 年前

    没有这样的语言特性,但是如果您必须经常实现一个接口,使得这种冗长变得相关,那么您可以编写自己的适配器。

    f.addWindowListener(WindowAdapter.window()
        .onClosing(ev -> ev.getWindow().dispose())
        .onClosed(ev -> System.out.println("closed"))
    );
    

    或者利用 import static :

    f.addWindowListener(window().onClosing(ev -> System.out.println("closing")));
    

    所以,继续你的例子

    f.addWindowListener(window().onClosing(Foo::doFoo).onActivated(Foo::doFoo));
    

    适配器:

    public class WindowAdapter implements WindowListener {
        static Consumer<WindowEvent> NO_OP = ev -> {};
        public static WindowAdapter window() {
            return new WindowAdapter(NO_OP, NO_OP, NO_OP, NO_OP, NO_OP, NO_OP, NO_OP);
        }
        final Consumer<WindowEvent> opened, closing, closed,
            iconified, deiconified, activated, deactivated;
    
        public WindowAdapter(Consumer<WindowEvent> opened, Consumer<WindowEvent> closing,
            Consumer<WindowEvent> closed, Consumer<WindowEvent> iconified,
            Consumer<WindowEvent> deiconified, Consumer<WindowEvent> activated,
            Consumer<WindowEvent> deactivated) {
            this.opened = opened;
            this.closing = closing;
            this.closed = closed;
            this.iconified = iconified;
            this.deiconified = deiconified;
            this.activated = activated;
            this.deactivated = deactivated;
        }
        public WindowAdapter onOpened(Consumer<WindowEvent> c) {
            Objects.requireNonNull(c);
            return new WindowAdapter(opened==NO_OP? c: opened.andThen(c),
                closing, closed, iconified, deiconified, activated, deactivated);
        }
        public WindowAdapter onClosing(Consumer<WindowEvent> c) {
            Objects.requireNonNull(c);
            return new WindowAdapter(opened, closing==NO_OP? c: closing.andThen(c),
                closed, iconified, deiconified, activated, deactivated);
        }
        public WindowAdapter onClosed(Consumer<WindowEvent> c) {
            Objects.requireNonNull(c);
            return new WindowAdapter(opened, closing, closed==NO_OP? c: closed.andThen(c),
                iconified, deiconified, activated, deactivated);
        }
        public WindowAdapter onIconified(Consumer<WindowEvent> c) {
            Objects.requireNonNull(c);
            return new WindowAdapter(opened, closing, closed,
              iconified==NO_OP? c: iconified.andThen(c), deiconified, activated, deactivated);
        }
        public WindowAdapter onDeiconified(Consumer<WindowEvent> c) {
            Objects.requireNonNull(c);
            return new WindowAdapter(opened, closing, closed, iconified,
                deiconified==NO_OP? c: deiconified.andThen(c), activated, deactivated);
        }
        public WindowAdapter onActivated(Consumer<WindowEvent> c) {
            Objects.requireNonNull(c);
            return new WindowAdapter(opened, closing, closed, iconified,
                deiconified, activated==NO_OP? c: activated.andThen(c), deactivated);
        }
        public WindowAdapter onDeactivated(Consumer<WindowEvent> c) {
            Objects.requireNonNull(c);
            return new WindowAdapter(opened, closing, closed, iconified,
                deiconified, activated, deactivated==NO_OP? c: deactivated.andThen(c));
        }
        @Override public void windowOpened(WindowEvent e) { opened.accept(e); }
        @Override public void windowClosing(WindowEvent e) { closing.accept(e); }
        @Override public void windowClosed(WindowEvent e) { closed.accept(e); }
        @Override public void windowIconified(WindowEvent e) { iconified.accept(e); }
        @Override public void windowDeiconified(WindowEvent e) { deiconified.accept(e); }
        @Override public void windowActivated(WindowEvent e) { activated.accept(e); }
        @Override public void windowDeactivated(WindowEvent e) { deactivated.accept(e); }
    }
    
        2
  •  1
  •   Didier L    6 年前

    建在屋顶上 Holger's idea ,这里是一个更简单的实现。API有点不同,但是您可以轻松地添加所有 on*()

    public class WindowListenerAdapter implements WindowListener {
        private Map<Integer, Consumer<WindowEvent>> listeners = new HashMap<>();
    
        public static WindowListenerAdapter adapter() {
            return new WindowListenerAdapter();
        }
    
        public WindowListenerAdapter register(int eventId, Consumer<WindowEvent> listener) {
            if (eventId < WindowEvent.WINDOW_FIRST || eventId > WindowEvent.WINDOW_LAST) {
                throw new IllegalArgumentException("Invalid event id: " + eventId);
            }
            listeners.merge(eventId, listener, Consumer::andThen);
            return this;
        }
    
        private void processEvent(WindowEvent e) {
            listeners.getOrDefault(e.getID(), i -> {}).accept(e);
        }
    
        @Override
        public void windowOpened(final WindowEvent e) {
            processEvent(e);
        }
    
        @Override
        public void windowClosing(final WindowEvent e) {
            processEvent(e);
        }
    
        @Override
        public void windowClosed(final WindowEvent e) {
            processEvent(e);
        }
    
        @Override
        public void windowIconified(final WindowEvent e) {
            processEvent(e);
        }
    
        @Override
        public void windowDeiconified(final WindowEvent e) {
            processEvent(e);
        }
    
        @Override
        public void windowActivated(final WindowEvent e) {
            processEvent(e);
        }
    
        @Override
        public void windowDeactivated(final WindowEvent e) {
            processEvent(e);
        }
    }
    

    并将其用作:

    f.addWindowListener(adapter().register(WINDOW_CLOSING, Foo::doFoo)
            .register(WINDOW_ACTIVATED, Foo::doFoo));
    

    你甚至可以加一个

    public static WindowListenerAdapter forWindow(Window f) {
        final WindowListenerAdapter adapter = adapter();
        f.addWindowListener(adapter);
        return adapter;
    }
    

    并将其用作:

    forWindow(f).register(WINDOW_CLOSING, Foo::doFoo)
            .register(WINDOW_ACTIVATED, Foo::doFoo);
    

    或者类似于

    public WindowListenerAdapter on(Window w) {
        w.addWindowListener(this);
        return this;
    }
    

    写:

    adapter().register(WINDOW_CLOSING, Foo::doFoo)
            .register(WINDOW_ACTIVATED, Foo::doFoo)
            .on(f);
    
        3
  •  0
  •   Peter Lawrey    6 年前

    您可以编写自己的类来容纳这些lambda,并根据需要调用它们。如果您经常这样做,可能会节省一些代码,但在您的示例中,最终可能会有更多的代码行。

        4
  •  0
  •   LuCio    6 年前

    看着 JEP draft: Concise Method Bodies 也许会有这样的事情:

        component.addWindowListener(new WindowListener() {
            public void windowClosing(e) -> Foo.doFoo(e);
            public void windowActivated(e) -> Foo.doFoo(e);
        });
    

        component.addWindowListener(new WindowListener() {
            public void windowClosing(e) = Foo::doFoo;
            public void windowActivated(e) = Foo::doFoo;
        });
    

    简洁的方法体避免了行噪声,并让您处理

    第一个代码使用 . 第二个代码使用请求的 方法引用 .

    虽然这还不是一个解决方案,但它可能会成为一个解决方案。让我们继续关注。

    推荐文章