2015-02-11 13 views
5

Sto cercando di rendere il mio codice più efficiente e sostituire un gruppo di istruzioni if ​​che ho scritto. Il mio programma fino ad ora controlla essenzialmente quale operatore (come +, -, ecc) viene inserito e poi lo calcola. Ad esempio 1 + 5 restituisce 6. Quando il programma valuta il simbolo tra il numero (il "+" nel mio esempio) controllerà l'operatore e quindi procederà di conseguenza. Per esempio, se si tratta di un "+", ci vorrà l'1 e aggiungere 5. Il codice funziona in questo modo:Sostituzione di istruzioni?

switch (op) { 
    case "+": // Addition 
     return args[0] + args[1]; 
    case "-": // Subtraction 
     return args[0] - args[1]; 
    case "*": // Multiplication 
     return args[0] * args[1]; 
    case "/": // Division 
     return args[0]/args[1]; 

Mi chiedo se è possibile sostituire l'intero blocco con un qualche tipo di dichiarazione che sarà rilevare l'operatore dalla stringa e convertirlo in un'operazione? Mi rendo conto che per alcuni operatori è probabilmente più semplice utilizzare le istruzioni switch, ma ne ho molte e c'è una differenza di 5-10 ms tra la valutazione dell'operatore nella parte superiore delle istruzioni switch e in basso.

+0

istruzioni switch con un sacco di casi sono già compilatore ottimizzato per qualcosa che esegue in modo paragonabile a un ricerca basata sull'hash, o almeno molto meglio della ricerca lineare if/else. – The111

risposta

10

In Java 8, è possibile utilizzare una mappa di funzioni lambda:

Map<String, IntBinaryOperator> operators = new HashMap<>(); 

operators.put("+", (a, b) -> a + b); 
operators.put("-", (a, b) -> a - b); 
operators.put("*", (a, b) -> a * b); 
operators.put("/", (a, b) -> a/b); 

... 

return operators.get(op).apply(args[0], args[1]); 

C'è di più indirezione qui, ma vi darà O (1) ammortizzato ricerca tempo.

+0

Grazie per l'aiuto, lo verificherò più tardi oggi. C'è un modo in cui questo può funzionare anche con le funzioni? Come se l'op fosse "sqrt", voglio chiamarlo Math.sqrt (args [0]). –

+0

@ThomasPaine Per radice quadrata, puoi provare operators.put ("sqrt", (a, b) -> Math.sqrt (args [0]). Anche se, dovresti provare a cercare una diversa interfaccia funzionale da usare diversa da IntBinaryOperator – CKing

+0

Questa ricerca hash sarà più efficiente della ricerca di switch ottimizzata del compilatore? – The111

2

La risposta è il Strategy Pattern - hai già il bell'esempio Java 8, ecco la versione pre-lambda (che mostra anche il motivo per cui lambda erano assolutamente necessarie):

public class CodeTest { 

    private static interface ArithmeticStrategy { 
     public double apply(double arg1, double arg2); 
    } 

    private static class AddArithmeticStrategy implements ArithmeticStrategy { 
     @Override 
     public double apply(double arg1, double arg2) { 
      return arg1 + arg2; 
     } 
    } 

    // ... other operations 

    private static Map<String, ArithmeticStrategy> OPS = new HashMap<>(); 
    static { 
     OPS.put("+", new AddArithmeticStrategy()); 
    } 

    public static void main(String[] args) { 
     // Add two numbers and print the result 
     System.out.println(
       OPS.get("+").apply(22.3, 35.4)); 
    } 
} 
0

se non si ha intenzione con Java 8 si potrebbe fare qualcosa di simile

public interface Op{ 
     int execute(int[] values); 
    } 
    public class Add implements Op{ 
     public int execute(int[] values){ 
      return values[0] + values[1]; 
     } 
    } 

allora tutto quello che vi serve è definire le operazioni mappa e popolano

private final Map<String, Op> operations = new HashMap<>(); 
operations.put("+", new Add()); 

quindi è possibile utilizzarlo chiamando operations.get(op).execute(args)

questa struttura vi permetterà di supportare le operazioni con uno due o anche 100 parametri