В Java, когда мы должны использовать частные методы экземпляра в интерфейсах? - PullRequest
9 голосов
/ 07 октября 2019

Начиная с Java 9, методы в интерфейсе могут быть закрытыми. Закрытый метод может быть статическим или методом экземпляра. Поскольку частные методы могут использоваться только в методах самого интерфейса, их использование ограничено тем, что они являются вспомогательными методами для других методов интерфейса.

Cay S. Horstmann, Core Java Volume I -Основы

Я понял, что мы можем использовать общие функции в приватных методах и не делать их доступными для общественности. Но у нас может быть два вида приватных методов:

  1. private
  2. private static

Использование private static методов понятно, нокогда мы должны использовать private методы? Здесь мы не имеем дело с экземплярами, так как это интерфейс, так почему создание методов private разрешено? Разве нам не нужны только private static методы?

Ответы [ 2 ]

3 голосов
/ 07 октября 2019

Интерфейсы используются для определения поведения объекта. Это означает, что все методов интерфейса доступны. При использовании методов по умолчанию мы можем предоставить стандартные реализации определенных методов, предлагая повторное использование кода через границы классов.

В некоторых случаях требуется функциональность (возможно, только для повторного использования кода в других стандартных методах ) но не должен быть выставлен, потому что это загрязнит пространства имен класса / объекта. Здесь частные методы по умолчанию пригодятся. Примерами частных методов по умолчанию могут быть фабрики, проверки или обработка состояния по умолчанию.

package com.company;

import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class Main {

  public static void main(final String[] args) {
    var messages =
        List.of(
            MessageQueue.newSubject("Message 1"),
            MessageQueue.newTopic("Message 2"),
            MessageQueue.newTopic("Message 3"));
    final MessageQueueAdapter1 queue1 = () -> messages;
    inspectQueue(queue1);
    final MessageQueueAdapter2 queue2 = () -> messages;
    inspectQueue(queue2);
  }

  private static void inspectQueue(final MessageQueue queue) {
    final List<Message> messagesWithSubject = queue.getMessagesWithSubject();
    assert messagesWithSubject.size() == 1 : "expected one message with 'Subject'";
    final List<Message> messagesWithTopic = queue.getMessagesWithTopic();
    assert messagesWithTopic.size() == 2 : "expected two message with 'Topic'";
    assert !queue.getMessages().isEmpty() && 3 == queue.getMessages().size()
        : "expected three messages in total";
  }

  @FunctionalInterface
  interface Message {
    private static boolean isPrefixedBy(final String message, final String prefix) {
      return message != null && !message.isEmpty() && message.startsWith(prefix);
    }

    default boolean hasSubject() {
      return isPrefixedBy(this.getMessage(), MessageQueue.PREFIX_SUBJECT);
    }

    default boolean hasTopic() {
      return isPrefixedBy(this.getMessage(), MessageQueue.PREFIX_TOPIC);
    }

    String getMessage();
  }

  interface MessageQueue {
    String PREFIX_SUBJECT = "Subject: ";

    String PREFIX_TOPIC = "Topic: ";

    private static Message newMessage(final String message) {
      return () -> message;
    }

    static Message newSubject(final String message) {
      return newMessage(PREFIX_SUBJECT + message);
    }

    static Message newTopic(final String message) {
      return newMessage(PREFIX_TOPIC + message);
    }

    List<Message> getMessages();

    List<Message> getMessagesWithSubject();

    List<Message> getMessagesWithTopic();
  }

  @FunctionalInterface
  interface MessageQueueAdapter1 extends MessageQueue {
    private static List<Message> filterBy(
        final List<Message> messages, final Predicate<Message> predicate) {
      return messages.stream().filter(predicate).collect(Collectors.toList());
    }

    /** {@inheritDoc} */
    @Override
    default List<Message> getMessagesWithSubject() {
      return filterBy(this.getMessages(), Message::hasSubject);
    }

    /** {@inheritDoc} */
    @Override
    default List<Message> getMessagesWithTopic() {
      return filterBy(this.getMessages(), Message::hasTopic);
    }
  }

  @FunctionalInterface
  interface MessageQueueAdapter2 extends MessageQueue {
    private List<Message> filterBy(final Predicate<Message> predicate) {
      return this.getMessages().stream().filter(predicate).collect(Collectors.toList());
    }

    /** {@inheritDoc} */
    @Override
    default List<Message> getMessagesWithSubject() {
      return filterBy(Message::hasSubject);
    }

    /** {@inheritDoc} */
    @Override
    default List<Message> getMessagesWithTopic() {
      return filterBy(Message::hasTopic);
    }
  }
}
2 голосов
/ 07 октября 2019

ОК, еще одна попытка ответить на вопросы ОП. Когда вам нужно вызвать другой нестатический метод на интерфейсе из закрытого метода, закрытый метод не может быть статическим. Например, была бы ошибка компиляции, если приведенный ниже закрытый метод был статическим:

public interface InterfaceWithMethods {
    public default void doSomething() {
        doSomethingCommon();
    }

    public default void doSomethingElse() {
        doSomethingCommon();
    }

    public void actuallyDoSomething();

    private void doSomethingCommon() {
        System.out.println("Do something first.");
        actuallyDoSomething();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...