operator not logical different and java instanceof control-flow

java - not - ¿Cambiar de instancia?



java operators (19)

Tengo una pregunta de usar el caso del interruptor para el instanceof objeto:

Por ejemplo: mi problema se puede reproducir en Java:

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

¿Cómo se implementaría utilizando switch...case ?


Aquí hay una forma funcional de lograrlo en Java 8 usando http://www.vavr.io/

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


Como se discutió en las respuestas principales, el enfoque tradicional de la POO es usar polimorfismo en lugar de un interruptor. Incluso hay un patrón de refactorización bien documentado para este truco: Reemplazar condicional con polimorfismo . Cuando llego a este enfoque, también me gusta implementar un objeto Nulo para proporcionar el comportamiento predeterminado.

Comenzando con Java 8, podemos usar lambdas y genéricos para darnos algo con lo que los programadores funcionales están muy familiarizados con: la coincidencia de patrones. No es una función de lenguaje central, pero la biblioteca Javaslang proporciona una implementación. Ejemplo desde el javadoc :

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

No es el paradigma más natural del mundo Java, así que utilícelo con precaución. Si bien los métodos genéricos le evitarán tener que encasillar el valor coincidente, nos falta una forma estándar de descomponer el objeto coincidente como en las clases de casos de Scala, por ejemplo.


Crear un Enum con nombres de clase.

public enum ClassNameEnum { A, B, C }

Encuentra el nombre de clase del objeto. Escribir un caso de cambio sobre la enumeración.

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

Espero que esto ayude.


Creo que hay razones para usar una instrucción switch. Si está utilizando xText código generado tal vez. O otro tipo de clases generadas por EMF.

instance.getClass().getName();

devuelve una Cadena del Nombre de Implementación de la Clase. es decir: org.eclipse.emf.ecore.util.EcoreUtil

instance.getClass().getSimpleName();

Devuelve la simple representación, es decir: EcoreUtil.


Este es un escenario típico donde el polimorfismo de subtipo ayuda. Haz lo siguiente

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

Entonces puedes simplemente llamar a do() sobre this .

Si no es libre de cambiar A , B y C , puede aplicar el patrón de visitante para lograr el mismo.


Esto funcionará más rápido y hará sentido en caso
- No puedes cambiar clases modelo (biblioteca externa)
- El proceso se ejecuta en un contexto simple de rendimiento.
- Tienes relativamente muchos ''casos''

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


No es posible que un conmutador solo funcione con los tipos byte, short, char, int, String y enumerados (y las versiones de objeto de los primitivos, también depende de su versión de java, las Strings se pueden switch en java 7)


No, no hay manera de hacer esto. Sin embargo, lo que podría querer hacer es considerar el Polymorphism como una forma de manejar este tipo de problemas.


Personalmente me gusta el siguiente código de 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"); });

Saldrá:

YYyy

El código de ejemplo utiliza cadenas, pero puede usar cualquier tipo de objeto, incluida la clase. por ejemplo, .myCase(this.getClass(), (o) -> ...

Necesita el siguiente fragmento de código:

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


Por si acaso si alguien lo lee:

La MEJOR solución en java es:

public enum Action { a{ void doAction(...){ // some code } }, b{ void doAction(...){ // some code } }, c{ void doAction(...){ // some code } }; abstract void doAction (...); }

Los GRANDES beneficios de tal patrón son:

  1. Simplemente hazlo como (NO hay interruptores):

    void someFunction ( Action action ) { action.doAction(...); }

  2. En caso de que si agrega una nueva acción llamada "d", DEBE usar el método de ejecución (...)

NOTA: Este patrón se describe en Joshua''s Bloch "Effective Java (2nd Edition)"


Qué tal esto ?

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


Sé que esto es muy tarde pero para futuros lectores ...

Tenga cuidado con los enfoques anteriores que se basan solo en el nombre de la clase de A , B , C ...

A menos que pueda garantizar que A , B , C ... (todas las subclases o implementadores de Base ) son finales , las subclases de A , B , C ... no se tratarán.

Aunque el enfoque if, elseif, elseif .. es más lento para un gran número de subclases / implementadores, es más preciso.


Si necesita "cambiar" a través del tipo de clase de "este" objeto, esta respuesta es la mejor https://.com/a/5579385/2078368

Pero si necesita aplicar "cambio" a cualquier otra variable. Sugeriría otra solución. Definir la siguiente interfaz:

public interface ClassTypeInterface { public String getType(); }

Implementa esta interfaz en cada clase que quieras "cambiar". Ejemplo:

public class A extends Something implements ClassTypeInterface { public final static String TYPE = "A"; @Override public String getType() { return TYPE; } }

Después de eso puedes usarlo de la siguiente manera:

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

Lo único que debería preocuparte es mantener los "tipos" únicos en todas las clases que implementan el ClassTypeInterface. No es un gran problema, porque en caso de cualquier intersección, recibe un error en tiempo de compilación para la declaración "switch-case".


Si no puede codificar una interfaz, puede utilizar una enumeración como intermediario:

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


Si puede manipular la interfaz común, puede agregar una enumeración y hacer que cada clase devuelva un valor único. No necesitarás un ejemplo o un patrón de visitante.

Para mí, la lógica tenía que estar escrita en la instrucción switch, no en el objeto en sí. Esta fue mi solución:

ClassA, ClassB, and ClassC implement CommonClass

Interfaz:

public interface CommonClass { MyEnum getEnumType(); }

Enumerar

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

Impl:

... 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; } ...

Si está en Java 7, puede poner valores de cadena para la enumeración y el bloque de mayúsculas y minúsculas seguirá funcionando.


Simplemente cree un Mapa donde la clase es la clave y la funcionalidad, es decir, lambda o similar, es el valor.

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

// por supuesto, refactoriza esto para inicializar solo una vez

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

Si necesita excepciones revisadas que implementar un FunctionalInterface que lanza la excepción y usarla en lugar de Runnable.


Usar instrucciones de cambio como esta no es la forma orientada a objetos. En su lugar, debe utilizar el poder del polimorfismo . Simplemente escribe

this.do()

Habiendo configurado previamente una clase base:

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

que es la clase base para A , B y 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() } }


Usted no puede La instrucción de switch solo puede contener declaraciones de case que sean constantes de tiempo de compilación y que se evalúen como un entero (Hasta Java 6 y una cadena en Java 7).

Lo que está buscando se llama "coincidencia de patrones" en la programación funcional.

Ver también Evitar instanceof en Java.


existe una forma aún más sencilla de emular una estructura de conmutador que utiliza instanceof; puede hacerlo creando un bloque de código en su método y denominándolo con una etiqueta. Luego usas las estructuras if para emular las declaraciones del caso. Si un caso es verdadero, entonces utiliza el salto LABEL_NAME para salir de su estructura de cambio improvisado.

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