Javaでは、いつインターフェイスでプライベートインスタンスメソッドを使用する必要がありますか?


9

Java 9以降、インターフェースのメソッドはプライベートにすることができます。プライベートメソッドは、静的メソッドまたはインスタンスメソッドです。プライベートメソッドは、インターフェイス自体のメソッドでのみ使用できるため、その使用は、インターフェイスの他のメソッドのヘルパーメソッドに限定されます。

Cay S. Horstmann、コアJavaボリュームI-基礎

共通の機能をプライベートメソッドに配置して、パブリックにアクセスできないようにすることができます。ただし、ここでは2種類のプライベートメソッドを使用できます。

  1. private
  2. private static

private staticメソッドの使用は理解できますが、いつprivateメソッドを使用する必要がありますか?これはインターフェースであるため、ここではインスタンスを扱っていませんが、privateメソッドの作成が許可されているのはなぜですか?private staticメソッドだけが必要ではないですか?


インターフェースには、他のインスタンスメソッドが呼び出すメソッドを含めることができますが、パブリックでの使用を目的としていません。
デイブニュートン

2
インターフェイスprivateを実装するクラスで、インターフェイスのインスタンスメソッドを呼び出してみてください。
Abra、

1
このようなプライベートメソッドは、インターフェイスから他のメソッドを呼び出す可能性があるため、private staticメソッドと同等ではなく、メソッドで置き換えることもできません。
Mark Rotteveel、

おそらくデフォルトのメソッド
モーリスペリー

回答:


2

OK、実際にOPの質問に答える別の試み。プライベートメソッドからインターフェイス上の別の非静的メソッドを呼び出す必要がある場合、プライベートメソッドを静的にすることはできません。たとえば、以下のプライベートメソッドが静的である場合、コンパイルエラーが発生します。

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

なぜそれが関係があるのですか?すべてのメソッドを「パブリックデフォルト」として実装することもできます。問題は、なぜ/どのようにして実装をxよりもyよりもzで選択するかについてです。
Florian Salihovic

2
@FlorianSalihovicは、このプライベートメソッドから別のメソッドを呼び出す必要がある場合、静的ではなく非静的を選択します。それが理由ではないですか?
jingx

あなたは間違った質問をしています。メソッドの可視性は、オブジェクトが相互にどのように相互作用するかについての可能性を狭める、または広げるために選択されます。通信する開発者は、自分のコードをどのように使用する必要があるか/使用する必要があるかを意図しているため、これは重要です。すべてを静的メソッドで実装するか、静的メソッドをまったく使用しないでください。他のオブジェクト/クラスが機能にアクセスすることの結果について考える必要があるので、質問は重要です。
Florian

2
@FlorianSalihovicしかし、私は人々のコメントから学んだように、OPは可視性や静的と非静的のどちらを使用するかについて尋ねていませんでした。代わりに、プライベート静的のように見えるのに、インターフェースで非静的プライベートメソッドが許可される理由を尋ねていました。私の答えは、非静的メソッドのみが機能するユースケースを提供しました。
jingx

3

インターフェイスは、オブジェクトの動作を定義するために使用されます。つまり、インターフェースのすべてのメソッドが公開されます。デフォルトのメソッドを使用する場合、定義されたメソッドの標準実装を提供して、クラスの境界を越えてコードを再利用できます。

場合によっては、機能が必要です(おそらく、さまざまな既定のメソッドでコードを再利用するためだけ)。ただし、クラス/オブジェクトの名前空間を汚染するため、公開しないでください。これは、プライベートなデフォルトメソッドが便利な場所です。プライベートデフォルトメソッドの例は、ファクトリ、検証、またはデフォルトの状態処理です。

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);
    }
  }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.