Есть ли краткая форма для переопределения методов в Java со ссылками на методы JAVA? - PullRequest
0 голосов
/ 16 октября 2018

У меня остаются ситуации, когда это было бы очень удобно

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 ]

0 голосов
/ 18 октября 2018

Есть ли какая-нибудь краткая форма для переопределения методов в Java со ссылками на методы?

Глядя на Черновик JEP: Краткие тела метода возможно, будет что-то вродечто:

    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;
    });

Использует синтаксис, чтобы показать, как

Тела краткого метода избегают шума линии и позволяют вам обрабатыватьанонимный класс, почти как семейство лямбд:

В первом коде используются выражения labda .Во втором коде используются запрошенные ссылки на метод .

Хотя это еще не решение, оно может стать им.Давайте оставаться в курсе.

0 голосов
/ 16 октября 2018

Такой языковой функции не существует, но если вам нужно реализовать интерфейс так часто, чтобы это многословие стало актуальным, вы можете написать свой собственный адаптер.

Например, с помощью адаптера ниже вы можете написать

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); }
}
0 голосов
/ 17 октября 2018

Опираясь на идею Хольгера , здесь есть реализация, которая немного проще.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);
0 голосов
/ 16 октября 2018

Вы можете написать свой собственный класс для хранения этих лямбд и вызывать их по мере необходимости.Если вы делаете это много, это может сохранить некоторый код, но в вашем примере вы можете получить больше строк кода.

...