source

Java 인터페이스의 옵션 메서드

nicesource 2023. 1. 8. 14:35
반응형

Java 인터페이스의 옵션 메서드

인터페이스를 Java로 구현하는 경우 해당 인터페이스에 지정된 메서드는 해당 인터페이스를 구현하는 하위 클래스에서 사용해야 합니다.

Collection 인터페이스 등 일부 인터페이스에는 옵션으로 코멘트가 되어 있는 메서드가 있습니다만, 이것은 정확히 무엇을 의미합니까?인터페이스에 지정된 모든 방법이 필요하다고 생각했기 때문에 조금 당황스러웠습니까?

여기 답변에 엄청난 혼란이 있는 것 같습니다.

Java 언어에서는 인터페이스의 모든 메서드가 해당 인터페이스의 모든 구현에 의해 구현되어야 합니다.마침표이 규칙에는 예외가 없습니다."수집은 예외"라고 말하는 것은 여기서 실제로 무슨 일이 일어나고 있는지에 대한 매우 애매한 이해를 시사한다.

인터페이스에 대한 준거에는 다음 두 가지 레벨이 있다는 것을 인식하는 것이 중요합니다.

  1. 자바 언어로 확인할 수 있는 것.요약하자면, 각 방법에 대해 어느 정도의 실장이 있는가?

  2. 실제로 계약을 이행하고 있습니다.즉, 구현은 인터페이스의 매뉴얼에 기재되어 있는 대로 이루어지고 있습니까?

    올바르게 기술된 인터페이스에는 구현에서 예상되는 내용을 정확하게 설명하는 문서가 포함됩니다.컴파일러가 이를 확인할 수 없습니다.당신은 그 문서를 읽고 그들이 말하는 대로 해야 해요.계약서에 기재되어 있는 대로 하지 않으면 컴파일러에 관한 한 인터페이스가 실장됩니다만, 이 실장은 불량이거나 무효가 됩니다.

할 때 서로 매우 세밀한 하는 대신 거친 Collections 한 인터페이스를 사용하는 대신 주로 매우 거친 인터페이스 세트만 사용하기로 결정했습니다.Collection,List,Set ★★★★★★★★★★★★★★★★★」Map특정 조작을 「옵션」으로 문서화합니다.이는 인터페이스의 세분화로 인한 조합의 폭발을 피하기 위한 것입니다.Java Collections API Design FAQ에서 다음을 참조하십시오.

문제를 상세하게 설명하기 위해 계층에 변경 가능성의 개념을 추가한다고 가정합니다.4개의 새로운 인터페이스가 필요합니다.ModifyCollection, ModifySet, ModifyList 및 ModifyMap.이전에는 단순한 계층구조였던 것이 이제는 지저분한 이질구조가 되었다.또한 제거 작업이 포함되지 않은 수정할 수 없는 컬렉션에 사용할 새 반복기 인터페이스가 필요합니다.이제 Unsupported Operation을 제거할 수 있습니다.예외?아쉽게도 아닙니다.

어레이에 대해 생각해 봅시다.대부분의 List 작업을 구현하지만 제거 및 추가 작업은 수행하지 않습니다.이들은 "고정 크기" 목록입니다.계층에서 이 개념을 캡처하려면 다음 2개의 새로운 인터페이스를 추가해야 합니다.Variable Size List 및 Variable Size Map.Variable Size Collection 및 Variable Size Set은 Modificable Collection 및 Modificable Set과 동일하기 때문에 추가할 필요는 없지만 일관성을 위해 추가할 수도 있습니다.또한 수정 불가능한 목록과 함께 추가 및 제거 작업을 지원하지 않는 새로운 종류의 ListIterator가 필요합니다.기존 4개의 인터페이스가 아닌 최대 10~12개의 인터페이스와 2개의 새로운 반복기 인터페이스가 추가되었습니다.말 끝났죠?아니요.

로그(복구 가능한 데이터 개체의 오류 로그, 감사 로그 및 저널 등)를 검토합니다.이들은 제거 및 설정(바꾸기)을 제외한 모든 목록 작업을 지원하는 자연스러운 추가 전용 시퀀스입니다.새로운 코어 인터페이스와 새로운 반복기가 필요합니다.

수정할 수 없는 컬렉션이 아닌 불변의 컬렉션은 어떻습니까?(클라이언트에 의해 변경할 수 없고 다른 이유로 변경되지 않는 컬렉션).많은 사람들은 이것이 가장 중요한 차이점이라고 주장합니다. 왜냐하면 여러 스레드가 동기화할 필요 없이 컬렉션에 동시에 액세스할 수 있기 때문입니다.이 지원을 유형 계층에 추가하려면 4개의 인터페이스가 더 필요합니다.

현재 최대 20개의 인터페이스와 5개의 반복기가 있으며, 실제로 어떤 인터페이스에도 잘 맞지 않는 컬렉션이 여전히 존재하고 있는 것은 거의 확실합니다.예를 들어 Map에서 반환되는 컬렉션뷰는 자연 삭제 전용 컬렉션입니다.또한 특정 요소를 값에 따라 거부하는 컬렉션이 있기 때문에 런타임 예외는 아직 삭제되지 않았습니다.

결국 런타임 예외를 발생시킬 수 있는 매우 작은 코어 인터페이스 세트를 제공함으로써 전체 문제를 회피하는 것은 건전한 엔지니어링상의 타협이라고 생각했습니다.

Collections API 내의 메서드가 "옵션 조작"으로 문서화되어 있는 경우, 메서드의 실장을 실장 중에 그대로 둘 수 있는 것도 아니고, 빈 메서드 본문을 사용할 수 있는 것도 아닙니다(예를 들어 많은 메서드가 결과를 반환할 필요가 있습니다).즉, 유효한 실장 선택(계약에 준거한 선택)은 를 던지는 것입니다.

해 주세요.왜냐하면 '이거'니까UnsupportedOperationException는 입니다.RuntimeException컴파일러에 관한 한 어떤 메서드 구현에서도 사용할 수 있습니다.를 들어, 를, 장, ation, 장, 실, 실, it, it, it, it, it, it, it, it, it, it, it, it, it, it, it, it, it, it, it, it, it, it, ,Collection.size()는, ,, 러, 이, 이, 이의 Collection.size()에는 이것이 허가되어 있지 않습니다.

차치하고: Java의 Collections API에서 사용되는 접근법은 다소 논란이 있다(그러나 아마도 처음 소개되었을 때보다 현재는 덜하다).이상적인 환경에서는, 인터페이스에는 옵션 조작이 없고, 대신에 세세한 인터페이스가 사용됩니다.문제는 Java가 추론된 구조 유형이나 교차 유형을 모두 지원하지 않는다는 것입니다. 따라서 "올바른 방법"을 시도하려고 하면 컬렉션의 경우 매우 다루기 어려워집니다.

인터페이스의 구현(추상적이지 않은) 클래스를 컴파일하려면 모든 메서드가 구현되어야 합니다.

, 그 구현이 단순한 예외로 간주되는 방법을 '미실행'으로 간주하는 경우(의 일부 방법처럼)Collectioninterface)으로 interface)를 합니다.Collection이 경우 interface는 예외이며 일반 케이스가 아닙니다.통상, 클래스의 실장은 모든 메서드를 실장해야 합니다.

컬렉션의 "선택사항"은 구현 클래스가 (위의 용어에 따라) 그것을 '실장'할 필요가 없으며 그냥 던질 수 있음을 의미합니다.

예 - 좋좋예 a a a a a a a a a 。add()수집 - 던지기만 합니다.NotSupportedException

Collection프로그래머를 비참하게 만드는 지저분한 상속 트리를 방지하기 위해 행해지고 있지만 대부분의 경우 이 패러다임은 권장되지 않으며 가능하면 피해야 한다.


업데이트:

Java 8부터 기본 방식이 도입되었습니다.

즉, 인터페이스는 실장을 포함한 메서드를 정의할 수 있습니다.
이것은, 새로운 기능이 필요 없는 코드의 일부에 대한 하위 호환성을 서포트하면서, 인터페이스에 기능을 추가할 수 있도록 하기 위해서 추가되었습니다.

메서드는 선언하는 모든 클래스에서 구현되지만 인터페이스의 정의를 사용합니다.

Java의 인터페이스는 클래스 구현 계약을 선언합니다.인터페이스의 모든 메서드를 구현해야 하지만 구현 클래스는 구현되지 않은 viz.를 공백으로 둘 수 있습니다.의도된 예로서

interface Foo {
  void doSomething();
  void doSomethingElse();
}

class MyClass implements Foo {
  public void doSomething() {
     /* All of my code goes here */
  }

  public void doSomethingElse() {
    // I leave this unimplemented
  }
}

해서 저는 떠났습니다.doSomethingElse()구현되지 않아 하위 클래스가 구현할 수 있습니다.그건 선택 사항입니다.

class SubClass extends MyClass {
    @Override
    public void doSomethingElse() {
      // Here's my implementation. 
    }
}

다만, 다른 유저가 말한 것처럼, Collection 인터페이스에 대해 이야기하고 있는 경우는 예외입니다.되지 않은 채로 있을 메서드가 수.UnsupportedOperationException외입니니다다

Collection 인터페이스의 옵션메서드는 메서드의 구현이 예외를 슬로우할 수 있지만 반드시 구현해야 함을 의미합니다.문서에 기재되어 있는 바와 같이

일부 수집 구현에는 포함할 수 있는 요소에 제한이 있습니다.예를 들어 null 요소를 금지하는 구현도 있고 요소의 유형에 제한이 있는 구현도 있습니다.부적격 요소를 추가하려고 하면 선택되지 않은 예외(일반적으로 Null Pointer)가 발생합니다.예외 또는 ClassCastException.부적격 요소가 존재하는지 쿼리하려고 하면 예외가 발생하거나 단순히 false가 반환될 수 있습니다.실장 중에는 전자의 동작을 나타내는 것과 후자의 동작을 나타내는 것이 있습니다.보다 일반적으로, 부적격 요소가 컬렉션에 삽입되지 않는 부적격 요소에 대한 연산을 시도하면 구현의 선택에 따라 예외가 발생하거나 성공할 수 있습니다.이러한 예외는, 이 인터페이스의 사양에서는 「옵션」으로 마크되어 있습니다.

은 제외).defaultJava 8+)의 구현이지만 구현이 기능적으로 유용한 것은 아닙니다.구체적으로는 다음과 같습니다.

  • 공백일 수 있습니다(빈 메서드).
  • 던질 도 있어UnsupportedOperationException 유사 (비슷한)

후자의 접근방식은 종종 컬렉션 클래스에서 채택됩니다.모든 메서드는 아직 구현되어 있지만 런타임에 호출되면 예외가 발생할 수 있습니다.

Java 8 이후에서는 이 질문에 대한 답변은 여전히 유효하지만 현재는 더 미묘한 차이를 보이고 있습니다.

첫째, 승인된 답변의 다음 문장은 올바른 상태로 유지됩니다.

  • 인터페이스는 계약에서 암묵적인 동작을 지정하는 것을 의미합니다(클래스를 구현하는 것이 유효한 것으로 간주되기 위해서는 따라야 하는 동작에 관한 규칙문).
  • 계약(약관)과 이행(규칙의 프로그램 코딩) 사이에 차이가 있다.
  • 인터페이스에 지정된 메서드는 항상 구현해야 합니다(어느 시점에서).

Java 8의 새로운 뉘앙스는 무엇일까요?옵션의 방법에 대해서는, 다음의 몇개의 방법이 적합합니다.

(가) 실시가 계약상 선택적인 것

"세 번째 문"은 추상 인터페이스 메서드가 항상 구현되어야 하며 이는 Java 8+에서 그대로 유지되어야 한다고 말합니다.그러나 Java Collections Framework에서와 같이 일부 추상 인터페이스 메서드를 계약에서 "옵션"으로 기술할 수 있습니다.

이 경우 인터페이스를 구현하는 작성자는 메서드를 구현하지 않을 수 있습니다.그러나 컴파일러는 구현을 고집하기 때문에 저자는 이 코드를 특정 구현 클래스에 필요하지 않은 임의의 메서드에 사용합니다.

public SomeReturnType optionalInterfaceMethodA(...) {
    throw new UnsupportedOperationException();
}

Java 7 이전 버전에서는 이것이 실제로는 유일한 "옵션 방식"이었습니다.즉, 구현되지 않은 경우 Unsupported Operation을 슬로우하는 방식입니다.예외.이 동작은 반드시 인터페이스 계약(예를 들어 Java Collections Framework의 옵션 인터페이스 방식)에 의해 지정됩니다.

(이) 재실시가 옵션인 것

Java 8은 기본 메서드의 개념을 도입했습니다.이것들은, 실장이 가능하고, 인터페이스 정의 자체에 의해서 제공되는 방식입니다.일반적으로 메서드 본문을 다른 인터페이스 메서드(즉, "primitive")를 사용하여 작성할 수 있는 경우 및 다음과 같은 경우에만 기본 메서드를 제공할 수 있습니다.this이렇게 하면 안 돼요'라고 합니다.

디폴트 방식은 (다른 인터페이스 방식 구현과 마찬가지로) 인터페이스의 계약을 이행해야 합니다.따라서 구현 클래스에서 인터페이스 메서드의 구현을 지정하는 것은 작성자의 재량에 달려 있습니다(동작이 목적에 적합한 경우).

이 새로운 환경에서는 Java Collections Framework를 다음과 같이 다시 작성할 수 있습니다.

public interface List<E> {
    :
    :
    default public boolean add(E element) {
        throw new UnsupportedOperationException();
    }
    :
    :
}

「의 방식 「 optional 」은, 「 optional 」입니다.add() Operation " Unsupported Operation " Unsupported Operation "을 .구현 클래스가 새로운 동작을 제공하지 않는 경우는 예외입니다.이는 정확히 원하는 동작이며 List 계약에 준거하고 있습니다.할 수 없는 , 「」의 은 「」입니다.add()는 옵션입니다.기본 동작은 필요한 동작이기 때문입니다.

이 경우 위의 "third 스테이트먼트"는 여전히 유효합니다.이는 메서드가 인터페이스 자체에 구현되어 있기 때문입니다.

. (3)Optional

입니다.Optional . 。Optional는 확실히 더인 클래스 합니다.null★★★★★★ 。

API를 하여 코딩할 때 으로 볼 수 에서는 임의의 늘(Java Streams API)와 .★★★★★★Optional크래쉬하지 하게 하는 늘 위한 을 제공합니다.class.class fluent는 null을 null로 합니다.

사실 저는 Surface View에서 영감을 받았습니다.Callback2 이게 공식적인 방법인 것 같아요

public class Foo {
    public interface Callback {
        public void requiredMethod1();
        public void requiredMethod2();
    }

    public interface CallbackExtended extends Callback {
        public void optionalMethod1();
        public void optionalMethod2();
    }

    private Callback mCallback;
}

클래스에서 옵션 메서드를 구현할 필요가 없는 경우 "콜백 구현"만 하면 됩니다.클래스에서 옵션 메서드를 구현해야 할 경우 "콜백 구현"만 하면 됩니다.확장"

영어가 엉망이라 미안해.

이 주제는...그래, 하지만 생각해 봐, 답이 하나 없어.인터페이스의 「디폴트 방식」에 대해 말하고 있습니다.예를 들어, 어떤 것(파괴자 같은 것)을 닫기 위한 클래스가 있다고 가정해 보겠습니다.세 가지 방법이 있다고 칩시다."doFirst", "doLast" 및 "onClose"라고 부릅니다.

그 타입의 오브젝트가 적어도 「onClose()」를 실현하고 싶다고 합니다만, 그 외의 오브젝트는 옵션입니다.

인터페이스의 「Default Methods」를 사용하면, 이것을 실현할 수 있습니다.알고 있습니다. 대부분의 타임은 인터페이스의 이유를 부정하지만 프레임워크를 설계하는 경우에는 유용합니다.

이런 식으로 실현하고 싶다면 다음과 같이 보일 것입니다.

public interface Closer {
    default void doFirst() {
        System.out.print("first ... ");
    }
    void onClose();
    default void doLast() {
        System.out.println("and finally!");
    }
}

예를 들어 "Test"라는 클래스에서 구현하면 컴파일러는 다음과 같이 문제 없습니다.

public class TestCloser implements Closer {
    @Override
    public void onClose() {
        System.out.print("closing ... ");
    }
}

출력:

first ... closing ... and finally!

또는

public class TestCloser implements Closer {
    @Override
    public void onClose() {
        System.out.print("closing ... ");
    }

    @Override
    public void doLast() {
        System.out.println("done!");
    }
}

출력:

first ... closing ... done!

모든 조합이 가능합니다."기본값"이 있는 것은 무엇이든 구현할 수 있지만, 없는 것은 반드시 구현해야 합니다.

내가 지금 대답하는 것이 완전히 틀리지 않기를 바란다.

모두 좋은 하루 되세요!

[edit1] :주의:이것은 Java 8에서만 동작합니다.

모든 컬렉션 구현의 상위 클래스인 grepCode의 AbstractCollection.java 코드를 살펴보면 옵션 메서드의 의미를 이해하는 데 도움이 됩니다.AbstractCollection 클래스의 add(e) 메서드에 대한 코드는 다음과 같습니다. add(e) 메서드는 수집 인터페이스에 따라 선택 사항입니다.

public boolean  add(E e) {

        throw new UnsupportedOperationException();
    } 

옵션 메서드는 상위 클래스에 이미 구현되어 있으며 UnsupportedOperation을 발생시킵니다.호출 시 예외입니다.수집을 변경할 수 있도록 하려면 수집 인터페이스에서 옵션 메서드를 덮어써야 합니다.

콜백 인터페이스를 실장하는 방법을 찾고 있었기 때문에 각 콜백에 대해 모든 방법을 실장하고 싶지 않았기 때문에 옵션 메서드를 실장할 필요가 있었습니다.

그래서 인터페이스를 사용하는 대신 다음과 같은 빈 구현 클래스를 사용했습니다.

public class MyCallBack{
    public void didResponseCameBack(String response){}
}

멤버 변수 CallBack을 다음과 같이 설정할 수 있습니다.

c.setCallBack(new MyCallBack() {
    public void didResponseCameBack(String response) {
        //your implementation here
    }
});

이렇게 불러주세요.

if(mMyCallBack != null) {
    mMyCallBack.didResponseCameBack(response);
}

이렇게 하면 콜백마다 모든 메서드를 구현할 필요가 없고 필요한 메서드만 덮어쓸 수 있습니다.

OP의 질문에 대한 답변은 아니지만 Java 8에서는 인터페이스에 기본 메서드를 추가할 수 있습니다.default인터페이스의 메서드시그니처에 배치되는 키워드는 클래스에 메서드를 덮어쓸 수 있는 옵션이 생기지만 반드시 덮어쓸 필요는 없습니다.

Oracle Java 컬렉션 튜토리얼:

코어 수집 인터페이스의 수를 관리할 수 있도록 하기 위해 Java 플랫폼에서는 각 수집 유형의 변형에 대해 별도의 인터페이스를 제공하지 않습니다.(이러한 변형에는 불변, 고정 크기 및 추가 전용이 포함될 수 있습니다).대신에, 각 인터페이스의 변경 조작은 옵션으로서 지정되어 있습니다.이 경우, 특정의 실장이 모든 조작을 서포트하지 않는 경우가 있습니다.지원되지 않는 작업이 호출되면 컬렉션에서 UnsupportedOperation이 느려집니다.예외입니다.실장은, 서포트하는 옵션의 조작을 문서화할 책임이 있습니다.Java 플랫폼의 모든 범용 구현은 모든 옵션 작업을 지원합니다.

인터페이스의 「옵션」메서드에 대해서는, 이 투고가 10년 가까이 된 것에 주의해 설명하겠습니다.

( @에 의해) 언급되었듯이 8에서는 에 Java 8을 사용할 수 .default「」. 은, 이 할 수 있는 가 없기 에서는 「이라고 부를 수 ).이것은 이 문제를 해결할 수 있는 한 가지 방법입니다.클래스의 실장에서는 디폴트 메서드를 실장할 필요가 없기 때문입니다(실장 관점에서는 「옵션」을 호출할 수 있습니다).다만, 실제로는, 실장 클래스가 이 메서드를 정의하고 있기 때문에, 실장 클래스는 이 메서드를 호출할 수 있는 것은 사실입니다.클래스에는 인터페이스에 의해 부과되는 (디폴트) 동작이 이미 포함되어 있기 때문에 실제로는 옵션 동작은 아닙니다.더 좋은 대안이 있는데 그건 나중에 얘기할게요.

두 번째 포인트는 "아무것도 하지 않는" 방법을 도입하는 것은 대부분의 경우 끔찍한 생각이라는 것입니다."아무것도 하지 마세요" 방법은 대부분의 시간이 득보다 실이 더 많은 부작용을 가져오고 잠재적으로, 여러분은 이러한 부작용을 결코 알지 못할 것입니다.예를 들어 JUnit 테스트를 사용하여 이 점을 설명하고 싶습니다."아무것도 안 함" 테스트 메서드를 여러 개 사용하여 테스트 클래스를 만들면 프레임워크는 이러한 메서드를 실행하고 실제로 테스트가 수행되지 않은 경우 통과된 것으로 표시합니다.이것은 꽤 위험한 부작용이다.이 시나리오를 "아무것도 안 함" 메서드를 포함하여 생성할 수 있는 공용 라이브러리로 확장하십시오.클라이언트는, 이러한 빈 실장을 인식하지 못하고, 아무것도 하지 않는 것을 모르고, 이러한 메서드를 호출할 수 있습니다.더 많은 예를 들 수 있지만, 제 답변의 요점은 그게 아닙니다.즉, "do nothing" 메서드를 구현하는 것은 "optional" 동작의 예가 아닙니다.이 메서드가 처음부터 구현되었다는 사실은 이것이 선택사항이 아니라는 점을 이미 증명하고 있습니다("아무것도 하지 않는" 동작은 존재하지 않는 동작과 동일하지 않습니다."

사용하고 있는 Java 버전에 관계없이 이 문제에 대한 최선의 해결책은 SOLID 원칙의 "I"를 따르는 것입니다. 인터페이스 분리 원칙ISP 를 사용하면, 옵션의 방식과 필요한 방식을 다른 인터페이스로 분리할 수 있습니다.예를 들어, Creating하기 위해Calculator 해서 용하려 a a a a a a a a and를 하려고 합니다.CalculatorOperations인터페이스입니다.그러나 계산기는 4개의 기본적인 연산(더하기, 빼기, 곱하기, 나눗셈)만 사용하면 되기 때문에 이 인터페이스에는 필요 이상의 연산이 있습니다.ISP는 클라이언트가 사용하지 않는 방식에 의존하도록 강요해서는 안 된다고 합니다.그래서 이 문제를 해결하는 가장 좋은 방법은CalculatorOperations를 들어, 2개의합니다.BasicOperations ★★★★★★★★★★★★★★★★★」AdvancedOperations다른 인터페이스를 사용하여 필수와 옵션 기능을 분리하면 클래스에 필요한 인터페이스를 구현하거나 Dependency Injection(DI; 의존성 주입)을 사용하여 필요한 동작을 주입(또는 삭제)할 수 있습니다.예를 들어, DI 를 사용하면, 버튼(Windows Calculator 등)을 클릭하는 것만으로 조작을 표시하거나 숨길 수 있습니다.

계산기 조작 인터페이스가 간단한 예라는 것은 알고 있습니다만, 요점은 Java의 인터페이스를 사용하여 필요한 조작과 옵션 조작을 명확하게 구분하는 가장 좋은 방법은 ISP라는 것입니다.

언급URL : https://stackoverflow.com/questions/10572643/optional-methods-in-java-interface

반응형