es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo hacer una lambda genérica que compare cualquier número de tipo idéntico.

Tengo la necesidad de reemplazar un operador de comparación en tiempo de ejecución, donde se compararían dos Números mediante GreaterThanOrEquals, LessThanOrEquals, Equals, etc. Pero idealmente no quiero replicar mi código para Integers, Doubles, Longs, Shorts, Floats y Bytes. Una parte de mis requisitos es mantener la operación en lambdas tanto como sea posible para mejorar el rendimiento.

Nota: Ambos valores siempre serán del mismo tipo. No tengo intención de hacer comparaciones de tipos mixtos.

Aquí hay un borrador de mi código. Intenté simplemente parametrizar el último método estático con Java.lang.Number, pero >= no funcionará en Number:

public class Expression {
public Param p1;
public Operator o;
public Param p2;

public Object eval() {
    return o.eval(p1.getValue(),p2.getValue());
}

}

public interface Operator{
Object eval(T p1,T p2);
}

public interface GreaterOrEqual extends Operator{
static Operator Integers() {
return (v1, v2) -> v1 >= v2;
}

static Operator<double> Doubles() {
    return (v1, v2) -> v1 >= v2;
}

static Operator<long> Longs() {
    return (v1, v2) -> v1 >= v2;
}

static Operator<number> generic() {
    // este no se compilará ya que "> =" no se puede aplicar a Java.lang.Number
    return (v1, v2) -> v1 >= v2;
}

}

Editar: Esta duplicación de código también significa que mi código de interfaz gráfica de usuario necesitará usar un “if (Param.value instanceof Integer) Expression.setOperator(GreaterOrEqual.Integers);” lo cual implica aún más duplicación de código.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Para evitar la duplicación de código y mantener la operación en las lambdas tanto como sea posible para mejorar el rendimiento, puede usar los genéricos comodín de Java para definir una sola interfaz de operador que funcione con todos los subtipos de Number. Así es como puede modificar su código:

    public class Expression<n extends="" number=""> {
        public Param<n> p1;
        public Operator<n> o;
        public Param<n> p2;
    
        public Object eval() {
            return o.eval(p1.getValue(), p2.getValue());
        }
    }
    
    public interface Operator<n extends="" number=""> {
        boolean compare(N n1, N n2);
    }
    
    public enum Comparison {
        GREATER_THAN_EQUALS(">=") {
            @Override
            public <n extends="" number=""> Operator<n> getOperator() {
                return (n1, n2) -> n1.doubleValue() >= n2.doubleValue();
            }
        },
        LESS_THAN_EQUALS("<=") {
            @Override
            public <n extends="" number=""> Operator<n> getOperator() {
                return (n1, n2) -> n1.doubleValue() <= n2.doubleValue();
            }
        },
        EQUALS("==") {
            @Override
            public <n extends="" number=""> Operator<n> getOperator() {
                return (n1, n2) -> n1.doubleValue() == n2.doubleValue();
            }
        };
    
        private final String symbol;
    
        Comparison(String symbol) {
            this.symbol = symbol;
        }
    
        public abstract <n extends="" number=""> Operator<n> getOperator();
    
        @Override
        public String toString() {
            return symbol;
        }
    }
    
    public class Param<n extends="" number=""> {
        private final N value;
    
        public Param(N value) {
            this.value = value;
        }
    
        public N getValue() {
            return value;
        }
    }
    

    En el código anterior, definimos una nueva clase parametrizada Expression<n extends="" number=""> que toma un parámetro de tipo N que representa el subtipo de Number con el que la expresión funcionará. También actualizamos la clase Param para que sea parametrizada con N.

    También definimos un nuevo enum Comparison que contiene los diferentes tipos de comparación que queremos admitir. Cada valor de enum anula el método getOperator para devolver el operador correspondiente para ese tipo de comparación.

    Finalmente, actualizamos la interfaz Operator para que también sea parametrizada con N, y modificamos las lambdas en el enum Comparison para usar doubleValue() en lugar de los operadores >= y <= para poder comparar cualquier subtipo de Number.

    Con este nuevo diseño, puede crear expresiones para cualquier subtipo de Number simplemente instanciando la clase Expression<n> con el parámetro de tipo deseado, y pasándole instancias correspondientes de Param<n> y Comparison. Ya no necesitas duplicar código o escribir declaraciones if para verificar el tipo de los parámetros.

Comments are closed.