2010-03-23 34 views
2

运营商解释的最快方式是switch语句来实现运营商解释在Java中是一个switch语句在Java中实现

public boolean accept(final int op, int x, int val) { 
    switch (op) { 
     case OP_EQUAL: 
      return x == val; 
     case OP_BIGGER: 
      return x > val; 
     case OP_SMALLER: 
      return x < val; 
     default: 
      return true; 
    } 
    } 

在这个简单的例子,很明显是最快的方法。现在想象你有1000个操作员。它会比类层次更快吗?当类层次结构比switch语句更有效时,是否有阈值? (在内存中显然不是)

abstract class Op { 
abstract public boolean accept(int x, int val); 
} 

然后每个运算符一个类。

编辑: 对不起,我应该从答案的外观更具体。 运营商是完全未知的,我使用JDK 1.4。没有选择。没有枚举。没有关闭。 ( )操作符由用户在众多选择中进行选择,为简单起见,设想一个包含1000个操作的GUI列表,当用户选择一个操作符时,选择switch语句的操作码,使用类层次结构,用户可以选择一个班级 我在问这个问题,因为有人必须先测试过它,我不想创建1000个班级和1000个虚假操作代码来测试它,如果没有人做到这一点,我会测试它并报告结果如果他们可以有任何意义。

+15

不要猜测。测量。 – skaffman 2010-03-23 19:48:23

+1

剖面仪功率。但是,我会考虑将我的操作符存储在由“op”索引的一组方法中。 – MonoThreaded 2010-03-23 19:57:21

+1

枚举看起来像是一个更好的选择,通过预定义的一组操作更易于读取和维护。 – Robin 2010-03-23 20:36:46

回答

2

我不知道什么是最快的,我也不认为有任何的保证。优化的代码是非常依赖于两种编译器和运行。

我做认为这很难击败switch语句。由于Java对可以切换的类型的限制,它可以很容易地编译到查找表中,这是关于您可以获得的最快访问。

+0

好吧,这也是我的直觉,switch语句是赢家甚至尽管这是糟糕的OOP。 我仍然想知道如果子类的方法解析可能会打败它。 => subClassOfAbstractOperator.operate(x,val); – Mordan 2010-03-24 23:39:46

0

如果调用方法已经决定使用哪个运算符值并调用accept(),那么最快的事情就是使用相同的调用方法进行内联比较。

另外,使用三种方法(或战略):

public boolean acceptGreater(int x, int val) { 
    return x > val; 
} 

public boolean acceptLess(int x, int val) { 
    return x < val; 
} 

public boolean acceptEquals(int x, int val) { 
    return x == val; 
} 
0

我不会看这纯粹是从一个原始性能一点,但我会评估这是一个重构的候选人,请参阅c2:Refactor Mercilessly 。我喜欢给予code resuability的回答:

  1. 如果您重复一次,请复制它。
  2. 如果您重复两次,请重构它。

我想确定将多个case语句添加为重复,然后重构实现Strategy Pattern
我会用策略后缀命名操作符类,并实现execute方法。

8

由于switch语句通常在jvm中使用查找表来实现,因此使用少量或大量的操作符可能会更快。这只是猜测;有一个明确的答案,你需要在它打算运行的系统上进行基准测试。

但是,这只是一个微优化你不应该关心,除非分析表明它可以真正有所作为。使用整数而不是特定的类(或枚举)使代码不易读。一个巨大的开关语句有1000个案例是一个糟糕的设计的标志。这将对使用操作符的代码产生影响; 不太可读,更多的错误,难以重构,...

并回到性能,这似乎是这里的目标。在难以阅读的设计糟糕的代码中,宏优化所需的更改变得更加困难。而这些优化通常比微型优化更像这个开关很多更重要的

9

编辑:

好吧,因为你必须使用JDK 1.4,我原来的答复是不走(左下图供参考)。我会猜想switch不像基于抽象类的解决方案那么快,当你看着apply(which,a,b)which.apply(a,b)调用。你只需要测试一下。

不过,测试时,你可能还需要考虑启动时间,内存占用等

ORIGINAL:

public enum OPERATION { 
    // ...operators+implementation, e.g.: 
    GREATER_THAN { public boolean apply(int a, int b) { return a > b; } }; 
    public abstract boolean apply(int a, int b); 
} 

用法:

OPERATION x = //..however you figure out which 
boolean result = x.apply(a,b); 

这是一个个案在有效的Java中用于枚举。它的工作方式与switch完全相同,只是不那么令人困惑。

+0

whoops-在Effective Java中,不是Java教程的踪迹。 – Carl 2010-03-24 01:01:41

0

我一直发现java switch语句没有我需要的那么强大。在他的last release lambdaj implements it智能使用闭包和Hamcrest匹配器。

1

使用表驱动方法,正如前面的海报指出的那样,您可以使用操作符作为数组的索引。存储在数组中的值可以是执行比较的类的实例。该数组可以静态初始化,或更好的按需(延迟加载模式)。

例如

// Interface and classes 
interface Operator { 
     boolean operate(int x, int y); 
} 

class EqualsOperator implements Operator { 
     boolean operate(int x, int y){ 
     return x==y; 
     } 
} 
class NotEqualsOperator implements Operator { 
     boolean operate(int x, int y){ 
     return x=!y; 
     } 
} 
... 

// Static initialization 
Operator[] operators = new Operator[n]; 
operator[0] = new EqualsOperator(); 
operator[1] = new NotEqualsOperator(); 
... 

// Switch 
public boolean accept(final int op, int x, int val) { 
    operator[op].operate(x,val); 
} 
+1

是的thx人。但问题是将声明 operator [op] .operate(x,val); 要比整个switch语句快。 – Mordan 2010-03-24 23:36:23

+0

只是简介它。但我想这个收益将会是纳秒级的,所以我不会花费太多精力。 – 2010-03-25 09:28:52