Di Java, kapan kita harus menggunakan metode instance pribadi di antarmuka?

9

Pada Java 9, metode dalam antarmuka bisa bersifat pribadi. Metode pribadi dapat berupa metode statis atau instan. Karena metode pribadi hanya dapat digunakan dalam metode antarmuka itu sendiri, penggunaannya terbatas pada metode penolong untuk metode antarmuka lainnya.

Cay S. Horstmann, Core Java Volume I - Fundamentals

Saya mengerti bahwa kita dapat menempatkan fungsionalitas umum dalam metode pribadi dan tidak membuatnya dapat diakses oleh publik. Tetapi kita dapat memiliki dua jenis metode pribadi di sini:

  1. private
  2. private static

Menggunakan private staticmetode dapat dimengerti, tetapi kapan kita harus menggunakan privatemetode? Kami tidak berurusan dengan contoh di sini karena ini adalah antarmuka, jadi mengapa membuat privatemetode diperbolehkan? Bukankah kita hanya perlu private staticmetode?

sg7610
sumber
Antarmuka dapat mencakup metode yang disebut metode instance lain, tetapi tidak dimaksudkan untuk konsumsi publik.
Dave Newton
2
Coba panggil privatemetode instance antarmuka di kelas yang mengimplementasikan antarmuka.
Abra
1
Metode pribadi semacam itu bisa memanggil metode lain dari antarmuka, sehingga tidak setara atau diganti dengan private staticmetode.
Mark Rotteveel
metode standar mungkin
Maurice Perry

Jawaban:

2

OK, upaya lain untuk benar-benar menjawab pertanyaan OP. Saat Anda perlu memanggil metode non-statis lain di antarmuka dari metode pribadi, metode pribadi tidak boleh statis. Misalnya, akan ada kesalahan kompilasi jika metode pribadi di bawah ini statis:

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();
    }
}
jingx
sumber
Mengapa itu relevan? Anda juga dapat menerapkan setiap metode sebagai "default publik". Pertanyaannya adalah tentang mengapa / dengan niat mana Anda memilih implementasi x atau y lebih dari z - bukan bagaimana.
Florian Salihovic
2
@FlorianSalihovic Anda akan memilih non-statis daripada statis ketika Anda perlu memanggil metode lain dari metode pribadi ini. Bukankah itu sebabnya?
jingx
Anda mengajukan pertanyaan yang salah. Visibilitas metode dipilih untuk mempersempit atau memperluas kemungkinan tentang bagaimana objek berinteraksi satu sama lain. Ini penting karena pengembang berkomunikasi bermaksud tentang bagaimana kode mereka harus / harus / dapat digunakan. Anda bisa mengimplementasikan semuanya dalam metode statis atau tidak menggunakan metode statis sama sekali. Pertanyaan ini penting karena kita perlu memikirkan konsekuensi dari memiliki objek / kelas lain yang dapat mengakses fungsionalitas, yang seharusnya tidak dapat diakses sama sekali.
Florian Salihovic
2
@FlorianSalihovic Tapi seperti yang saya pelajari dari komentar orang-orang, OP tidak bertanya tentang visibilitas atau kapan harus menggunakan statis vs non-statis, sebaliknya mereka bertanya mengapa metode privat non-statis bahkan diperbolehkan pada antarmuka ketika statis swasta tampaknya cukup. Jawaban saya memberikan kasus penggunaan di mana hanya metode non-statis akan bekerja.
jingx
3

Antarmuka digunakan untuk mendefinisikan perilaku objek. Ini berarti semua metode antarmuka terpapar. Saat menggunakan metode default, kami dapat memberikan implementasi standar dari metode yang didefinisikan, menawarkan penggunaan kembali kode melintasi batas kelas.

Dalam beberapa kasus, fungsionalitas diperlukan (mungkin hanya untuk penggunaan kembali kode dalam metode standar yang berbeda ) tetapi tidak boleh diekspos karena akan mencemari ruang kelas '/ objek. Di sinilah metode standar pribadi berguna. Contoh metode default pribadi dapat berupa pabrik, validasi, atau penanganan keadaan default.

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);
    }
  }
}
Florian Salihovic
sumber