programing

switch 문에서 instance of operator를 사용할 수 있습니까?

projobs 2022. 8. 10. 23:56
반응형

switch 문에서 instance of operator를 사용할 수 있습니까?

나는스위치케이스를 사용하는에질문이 있습니다 대해 것에 스위치 사건을 이용하여 질문을 가지고 있다.instanceof개체:오브젝트:

예: Java에서 문제를 재현할 수 있습니다.

if(this instanceof A)
    doA();
else if(this instanceof B)
    doB();
else if(this instanceof C)
    doC():

어떻게 사용하여 를 어떻게 구현됩니까를 사용 시행할 것이다?switch...case

이것은 서브타입 다형이 도움이 되는 전형적인 시나리오입니다.다음을 수행합니다.

interface I {
  void do();
}

class A implements I { void do() { doA() } ... }
class B implements I { void do() { doB() } ... }
class C implements I { void do() { doC() } ... }

그럼 단순히그럼그냥 전화하시면 됩니다 부를 수 있습니다.do()에에this..

만약 당신이 변경할수 없는 경우를 바꿀 자유롭지 못하다.A,,B그리고 ,그리고.C, 방문객 카드를 패턴이 같은을 달성하기 위해 신청할 수 있다.방문자 패턴을 적용하여 동일한 결과를 얻을 수 있습니다.

인터페이스를 코드화할 수 없는 경우는, 중간자로서 열거를 사용할 수 있습니다.

public A() {

    CLAZZ z = CLAZZ.valueOf(this.getClass().getSimpleName());
    switch (z) {
    case A:
        doA();
        break;
    case B:
        doB();
        break;
    case C:
        doC();
        break;
    }
}


enum CLAZZ {
    A,B,C;

}

한 작성하다 만들기Map열쇠 어디있는 곳열쇠가는Class<?>그리고 값이 표현(또는 유사한 람다).값은 식(양)입니다.★★★★★★★★★★★★★★★★★★:

Map<Class,Runnable> doByClass = new HashMap<>();
doByClass.put(Foo.class, () -> doAClosure(this));
doByClass.put(Bar.class, this::doBMethod);
doByClass.put(Baz.class, new MyCRunnable());

// of course, refactor this to only initialize once

doByClass.get(getClass()).run();

를 하십시오.FunctionalInterfaceException.Runnable.


다음은 이 접근방식이 어떻게 코드를 단순화할 수 있는지를 보여주는 전후 실제 단어입니다.

지도에 리팩터링하기 전의 코드:

private Object unmarshall(
  final Property<?> property, final Object configValue ) {
  final Object result;
  final String value = configValue.toString();

  if( property instanceof SimpleDoubleProperty ) {
    result = Double.parseDouble( value );
  }
  else if( property instanceof SimpleFloatProperty ) {
    result = Float.parseFloat( value );
  }
  else if( property instanceof SimpleBooleanProperty ) {
    result = Boolean.parseBoolean( value );
  }
  else if( property instanceof SimpleFileProperty ) {
    result = new File( value );
  }
  else {
    result = value;
  }

  return result;
}

지도에 리팩터링한 후 코드:

private final Map<Class<?>, Function<String, Object>> UNMARSHALL = 
Map.of(
  SimpleBooleanProperty.class, Boolean::parseBoolean,
  SimpleDoubleProperty.class, Double::parseDouble,
  SimpleFloatProperty.class, Float::parseFloat,
  SimpleFileProperty.class, File::new
);

private Object unmarshall(
  final Property<?> property, final Object configValue ) {
  return UNMARSHALL
    .getOrDefault( property.getClass(), ( v ) -> v )
    .apply( configValue.toString() );
}

이를 통해 반복을 방지하고 거의 모든 분기 명령문을 제거하며 유지보수를 간소화할 수 있습니다.

누군가 읽을 경우를 대비해서:

Java의 BEST 솔루션은 다음과 같습니다.

public enum Action { 
    a{
        void doAction(...){
            // some code
        }

    }, 
    b{
        void doAction(...){
            // some code
        }

    }, 
    c{
        void doAction(...){
            // some code
        }

    };

    abstract void doAction (...);
}

이러한 패턴의 큰 장점은 다음과 같습니다.

  1. 다음과 같이 하면 됩니다(스위치는 전혀 없습니다).

    void someFunction ( Action action ) {
        action.doAction(...);   
    }
    
  2. "d"라는 새로운 액션을 추가할 경우 doAction(...) 메서드를 반드시 구현해야 합니다.

메모: 이 패턴은 Joshua의 Bloch "Effective Java (2nd Edition)"에 설명되어 있습니다.

그럴수는 없어요.switch에는 '''만 할 수 .case컴파일 시간 상수이며 정수(Java 6까지 및 Java 7에서는 문자열)로 평가되는 문장.

기능 프로그래밍에서는 패턴 매칭이라고 부릅니다.

자세한 내용은 Java의 인스턴스 회피

상위 답변에서 설명한 바와 같이 기존의 OOP 접근법은 스위치 대신 다형성을 사용하는 것입니다.이 트릭에 대한 리팩터링 패턴도 잘 문서화되어 있습니다.조건식을 다형성으로 대체합니다.이 접근법에 도달할 때마다 기본 동작을 제공하는 Null 개체도 구현하고 싶습니다.

Java 8부터는 람다와 제네릭스를 사용하여 프로그래머들이 매우 익숙한 패턴 매칭을 제공할 수 있습니다.핵심 언어 기능은 아니지만 VAVR 라이브러리(이전 Javaslang 라이브러리)는 하나의 구현을 제공합니다.문서의 예:

Match.ofType(Number.class)
    .caze((Integer i) -> i)
    .caze((String s) -> new BigDecimal(s))
    .orElse(() -> -1)
    .apply(1.0d); // result: -1

Java 세계에서 가장 자연스러운 패러다임은 아니니 주의해서 사용하세요.일반적인 메서드를 사용하면 일치하는 값을 입력할 필요가 없지만 Scala의 사례 클래스와 같이 일치하는 개체를 분해하는 표준 방법이 없습니다.

아쉽게도 switch-case 스테이트먼트에서는 일정한 표현이 요구되기 때문에 즉시 사용할 수 없습니다.이를 극복하기 위해 예를 들어 enum 값을 클래스 이름과 함께 사용하는 방법이 있습니다.

public enum MyEnum {
   A(A.class.getName()), 
   B(B.class.getName()),
   C(C.class.getName());

private String refClassname;
private static final Map<String, MyEnum> ENUM_MAP;

MyEnum (String refClassname) {
    this.refClassname = refClassname;
}

static {
    Map<String, MyEnum> map = new ConcurrentHashMap<String, MyEnum>();
    for (MyEnum instance : MyEnum.values()) {
        map.put(instance.refClassname, instance);
    }
    ENUM_MAP = Collections.unmodifiableMap(map);
}

public static MyEnum get(String name) {
    return ENUM_MAP.get(name);
 }
}

그러면 다음과 같이 switch 문을 사용할 수 있습니다.

MyEnum type = MyEnum.get(clazz.getName());
switch (type) {
case A:
    ... // it's A class
case B:
    ... // it's B class
case C:
    ... // it's C class
}

이제 Java를 통해 OP 방식으로 전환할 수 있습니다.스위치 패턴 매칭이라고 합니다.현재 드래프트 중이지만, 최근 스위치로 얼마나 많은 작업을 하고 있는지 보고 있으면 충분히 할 수 있을 것 같습니다.JEP의 예는 다음과 같습니다.

String formatted;
switch (obj) {
    case Integer i: formatted = String.format("int %d", i); break;
    case Byte b:    formatted = String.format("byte %d", b); break;
    case Long l:    formatted = String.format("long %d", l); break;
    case Double d:  formatted = String.format("double %f", d); break;
    case String s:  formatted = String.format("String %s", s); break
    default:        formatted = obj.toString();
}  

또는 람다 구문을 사용하여 값을 반환합니다.

String formatted = 
    switch (obj) {
        case Integer i -> String.format("int %d", i)
        case Byte b    -> String.format("byte %d", b);
        case Long l    -> String.format("long %d", l); 
        case Double d  -> String.format("double %f", d); 
        case String s  -> String.format("String %s", s); 
        default        -> obj.toString();
    };

어떤 식으로든 스위치로 멋진 일을 해왔죠

늦은 건 알지만 미래의 독자들을 위해...

A, B, C의 클래스 이름만을 기반으로 하는 위의 접근법에 주의하십시오.

A, B, C…(베이스의 모든 서브클래스 또는 실장자)가 최종임을 보증할 수 없는 한, A, B, C…의 서브클래스는 취급되지 않습니다.

if, else, else, if, else, else.. 접근법이 다수의 서브클래스/실장자에 대해 느리더라도 더 정확합니다.

자바 7 이상

public <T> T process(Object model) {
    switch (model.getClass().getSimpleName()) {
    case "Trade":
        return processTrade((Trade) model);
    case "InsuranceTransaction":
        return processInsuranceTransaction((InsuranceTransaction) model);
    case "CashTransaction":
        return processCashTransaction((CashTransaction) model);
    case "CardTransaction":
        return processCardTransaction((CardTransaction) model);
    case "TransferTransaction":
        return processTransferTransaction((TransferTransaction) model);
    case "ClientAccount":
        return processAccount((ClientAccount) model);
    ...
    default:
        throw new IllegalArgumentException(model.getClass().getSimpleName());
    }
}

문자열 하면 더 .getSimpleName상수를 도입하고 전체 클래스 이름을 사용하는 경우:

public static final TRADE = Trade.class.getName();
...
switch (model.getClass().getName()) {
case TRADE:

아니, 이건 방법이 없어.그러나 다형성을 이러한 문제를 해결하는 방법으로 고려하는 것이 좋습니다.

이와 같은 switch 문을 사용하는 것은 객체 지향 방식이 아닙니다.대신 다형성의 힘을 사용해야 한다.간단하게 쓰기

this.do()

이전에 기본 클래스를 설정한 경우:

abstract class Base {
   abstract void do();
   ...
}

입니다.A,B ★★★★★★★★★★★★★★★★★」C:

class A extends Base {
    void do() { this.doA() }
}

class B extends Base {
    void do() { this.doB() }
}

class C extends Base {
    void do() { this.doC() }
}

저는 개인적으로 다음 Java 1.8 코드를 좋아합니다.

    mySwitch("YY")
            .myCase("AA", (o) -> {
                System.out.println(o+"aa");
            })
            .myCase("BB", (o) -> {
                System.out.println(o+"bb");
            })
            .myCase("YY", (o) -> {
                System.out.println(o+"yy");
            })
            .myCase("ZZ", (o) -> {
                System.out.println(o+"zz");
            });

유언 출력:

YYyy

하지만 Class 등 할 수 를 들어 Class 등입니다..myCase(this.getClass(), (o) -> ...

다음 스니펫이 필요합니다.

public Case mySwitch(Object reference) {
    return new Case(reference);
}

public class Case {

    private Object reference;

    public Case(Object reference) {
        this.reference = reference;
    }

    public Case myCase(Object b, OnMatchDo task) {
        if (reference.equals(b)) {
            task.task(reference);
        }
        return this;
    }
}

public interface OnMatchDo {
    public void task(Object o);
}

int, 및 수 버전에 ).은 " ", ", ", ", ", ", ", ", ", ", " 문자열"이 될 수 .스트링switched on Java 7)

공통 인터페이스를 조작할 수 있는 경우 열거형을 추가하여 각 클래스에서 원하는 값을 반환할 수 있습니다.인스턴스 또는 방문자 패턴이 필요하지 않습니다.

이 논리는 오브젝트 자체가 아니라 스위치스테이트먼트에 기재되어 있어야 합니다.이것이 저의 해결책이었습니다.

ClassA, ClassB, and ClassC implement CommonClass

인터페이스:

public interface CommonClass {
   MyEnum getEnumType();
}

열거:

public enum MyEnum {
  ClassA(0), ClassB(1), ClassC(2);

  private int value;

  private MyEnum(final int value) {
    this.value = value;
  }

  public int getValue() {
    return value;
  }

영향:

...
  switch(obj.getEnumType())
  {
    case MyEnum.ClassA:
      ClassA classA = (ClassA) obj;
    break;

    case MyEnum.ClassB:
      ClassB classB = (ClassB) obj;
    break;

    case MyEnum.ClassC:
      ClassC classC = (ClassC) obj;
    break;
  }
...

Java 7 의 경우는, enum 에 문자열 값을 입력할 수 있습니다.스위치 케이스 블록은 계속 동작합니다.

이건 어때?

switch (this.name) 
{
  case "A":
    doA();
    break;
  case "B":
    doB();
    break;
  case "C":
    doC();
    break;
  default:
    console.log('Undefined instance');
}

switch 스테이트먼트를 사용할 이유가 있다고 생각합니다.xText 생성 코드를 사용하는 경우.또는 다른 종류의 EMF 생성 클래스입니다.

instance.getClass().getName();

는 클래스 실장명의 문자열을 반환합니다.예를 들어 org.disc.emf.ecore.disc.disc.disc.에코루틸

instance.getClass().getSimpleName();

단순 표현(EcoreUtil)을 반환합니다.

클래스 타입의 「이」오브젝트를 「전환」할 필요가 있는 경우는, 다음의 대답이 최선입니다.https://stackoverflow.com/a/5579385/2078368

그러나 다른 변수에 "스위치"를 적용해야 하는 경우.저는 다른 해결책을 제안합니다.다음의 인터페이스를 정의합니다.

public interface ClassTypeInterface {
    public String getType();
}

「전환」하는 모든 클래스에 이 인터페이스를 실장합니다.예:

public class A extends Something implements ClassTypeInterface {

    public final static String TYPE = "A";

    @Override
    public String getType() {
        return TYPE;
    }
}

그 후 다음과 같이 사용할 수 있습니다.

switch (var.getType()) {
    case A.TYPE: {
        break;
    }
    case B.TYPE: {
        break;
    }
    ...
}

유일하게 주의해야 할 것은 ClassTypeInterface를 구현하는 모든 클래스에서 "type"을 고유하게 유지하는 것입니다.어떤 교차로라도 "switch-case" 문장의 컴파일 시간 오류가 발생하므로 큰 문제가 되지 않습니다.

클래스 이름을 사용하여 Enum을 만듭니다.

public enum ClassNameEnum {
    A, B, C
}

개체의 클래스 이름을 찾습니다.Enum 위에 스위치 대소문자를 씁니다.

private void switchByClassType(Object obj) {

        ClassNameEnum className = ClassNameEnum.valueOf(obj.getClass().getSimpleName());

        switch (className) {
            case A:
                doA();
                break;
            case B:
                doB();
                break;
            case C:
                doC();
                break;
        }
    }
}

이게 도움이 됐으면 좋겠다.

다음은 http://www.vavr.io/을 사용하여 Java 8에서 이를 실현하는 기능적인 방법입니다.

import static io.vavr.API.*;
import static io.vavr.Predicates.instanceOf;
public Throwable liftRootCause(final Throwable throwable) {
        return Match(throwable).of(
                Case($(instanceOf(CompletionException.class)), Throwable::getCause),
                Case($(instanceOf(ExecutionException.class)), Throwable::getCause),
                Case($(), th -> th)
        );
    }

스위치 스테이트먼트는 쓸 수 없지만, 각 타입의 특정 처리에 분기할 수 있습니다.이 방법 중 하나는 표준 더블 디스패치메커니즘을 사용하는 것입니다.유형에 따라 "전환"하는 예로는 Jersey Exception Mapper를 들 수 있습니다.여기에는 다수의 예외를 오류 응답에 매핑해야 합니다.이 경우, 보다 좋은 방법(즉, 각 예외를 에러 응답으로 변환하는 폴리모픽 방식 사용)이 있을 수 있지만, 이중 디스패치 메커니즘을 사용하는 것은 여전히 유용하고 실용적입니다.

interface Processable {
    <R> R process(final Processor<R> processor);
}

interface Processor<R> {
    R process(final A a);
    R process(final B b);
    R process(final C c);
    // for each type of Processable
    ...
}

class A implements Processable {
    // other class logic here

    <R> R process(final Processor<R> processor){
        return processor.process(this);
    }
}

class B implements Processable {
    // other class logic here

    <R> R process(final Processor<R> processor){
        return processor.process(this);
    }
}

class C implements Processable {
    // other class logic here

    <R> R process(final Processor<R> processor){
        return processor.process(this);
    }
}

「스위치」가 필요한 경우는, 다음과 같이 실시할 수 있습니다.

public class LogProcessor implements Processor<String> {
    private static final Logger log = Logger.for(LogProcessor.class);

    public void logIt(final Processable base) {
        log.info("Logging for type {}", process(base));
    }

    // Processor methods, these are basically the effective "case" statements
    String process(final A a) {
        return "Stringifying A";
    }

    String process(final B b) {
        return "Stringifying B";
    }

    String process(final C c) {
        return "Stringifying C";
    }
}

instanceof를 사용하는 스위치 구조를 에뮬레이트하는 보다 간단한 방법이 있습니다.이 방법은 메서드에 코드 블록을 만들고 라벨을 붙여 이름을 붙이는 것입니다.그런 다음 if structures를 사용하여 케이스 스테이트먼트를 에뮬레이트합니다.케이스가 참일 경우 브레이크 LABEL_NAME을 사용하여 임시 스위치 구조에서 빠져나갑니다.

        DEFINE_TYPE:
        {
            if (a instanceof x){
                //do something
                break DEFINE_TYPE;
            }
            if (a instanceof y){
               //do something
                break DEFINE_TYPE;
            }
            if (a instanceof z){
                // do something
                break DEFINE_TYPE;
            }
        }

Eclipse Modeling Framework는 상속도 고려하는 흥미로운 아이디어를 가지고 있습니다.기본 개념은 스위치인터페이스에 정의되어 있습니다.스위칭은 doSwitch 메서드를 호출하여 이루어집니다.

정말 흥미로운 것은 구현이다.관심 유형별로

public T caseXXXX(XXXX object);

메서드를 구현해야 합니다(기본 구현이 null을 반환함).doSwitch 실장에서는 오브젝트의 모든 유형 계층에 대해 caseXX 메서드를 호출하려고 합니다.다음과 같은 것:

BaseType baseType = (BaseType)object;
T result = caseBaseType(eAttribute);
if (result == null) result = caseSuperType1(baseType);
if (result == null) result = caseSuperType2(baseType);
if (result == null) result = caseSuperType3(baseType);
if (result == null) result = caseSuperType4(baseType);
if (result == null) result = defaultCase(object);
return result;

실제 프레임워크에서는 클래스별로 정수 ID가 사용되므로 로직은 실제로는 순수 스위치입니다.

public T doSwitch(Object object) {
    return doSwitch(object.class(), eObject);
}

protected T doSwitch(Class clazz, Object object) {
    return doSwitch(getClassifierID(clazz), object);
}

protected T doSwitch(int classifierID, Object theObject) {
    switch (classifierID) {
    case MyClasses.BASETYPE:
    {
      BaseType baseType = (BaseType)object;
      ...
      return result;
    }
    case MyClasses.TYPE1:
    {
      ...
    }
  ...

ECoreSwitch의 완전한 실장을 보면 보다 나은 아이디어를 얻을 수 있습니다.

if(){} else if{} 단일 파일을 kotlin으로 전환하여 식을 와 조합하여 switch-like 를 사용하는 것을 검토해 주십시오.is환입니니다다

어떤 경우에도 Kotlin과 Java 파일은 프로젝트에 공존할 수 있으며 JVM에서 실행할 수 있는 jar를 만들 수 있습니다.

when (this) { //switch-like statement in kotlin supporting class-pattern-matching and smart casts via `is` operator.
    is A -> doA()
    is B -> doB()
    is C -> doC()
}

언급URL : https://stackoverflow.com/questions/5579309/is-it-possible-to-use-the-instanceof-operator-in-a-switch-statement

반응형