可以尝试catch用于代码优化吗?

时间:2014-09-24 12:34:01

标签: java nullpointerexception try-catch

让我说我有以下课程:

public class RectangularPrism{
    public Integer width;
    public Integer height;
    public Integer depth;

    //setters and getters
}

我用它来计算所有棱镜的体积总和。我有两种计算方法。哪一个更好?

这个使用条件运算符

public Integer volumeSum(List<RectangularPrism> prismList){
        Integer sum = 0;
        for(RectangularPrism prism: prismList){
            Integer width = prism.getWidth() == null ? 0 : prism.getWidth();
            Integer height = prism.getHeight() == null ? 0 : prism.getHeight();
            Integer depth = prism.getDepth() == null ? 0 : prism.getDepth();
            sum += width * height * depth;
        }
        return sum;
    }

这个使用尝试捕获

public Integer volumeSum(List<RectangularPrism> prismList){
        Integer sum;
        for(RectangularPrism prism: prismList){
            try {
                Integer width = prism.getWidth();
                Integer height = prism.getHeight();
                Integer depth = prism.getDepth();
                sum += width * height * depth;
            }catch( NullPointerException e){}
        }
        return sum;
    }

哪一个会更好如果我的班级有100个或更多的字段来决定结果?

使用尝试捕获来处理 null 值是否可以?

3 个答案:

答案 0 :(得分:13)

这在每个级别都是一个坏主意。

  1. try-catch实际上更慢(如果确实有异常抛出)
  2. 您在非例外情​​况下使用例外(即正常控制流程),这在概念上是错误的。
  3. 如果try-catch区块中的任何其他内容抛出合法的NPE,则无法告知发生了什么。 (想象一下例如prism本身为空时的情况。)
  4. 很难从代码中找出你的意图。使用?:运算符检查空值是一个众所周知的模式,每个人都会认识到。
  5. 一个空的catch块是一个很大的禁忌,可能是最可靠的生成错误的方法,需要花费很长时间来追踪。
  6. 在这种情况下,两个片段甚至不等同,因为在“异常驱动”中,null值将意味着将跳过try块的其余部分。当然sum仍然是正确的,但这只是巧合。
  7. 如果您真的想提高性能,请不要使用Integer和其他包装类进行简单计算,而是使用相应的原语(在本例中为int)。额外的好处是你突然不必再担心null了,因为原始值永远不会是null

    总而言之:永远不要这样做。

    说真的,不要。每次你这样做,一只可爱的小猫死了。 enter image description here

答案 1 :(得分:3)

您永远不应该使用try-catch来处理程序的控制流程。

始终使用已建立的方法,在这种情况下,请检查第一个代码示例中的null。

答案 2 :(得分:0)

我知道这不会回答这个问题(可以try .. catch用于代码优化),但我认为你应该很少考虑null值:你应该强制执行(widthheightdepth)如果是对象的固有属性,则为非null

我的意思是,您正在构建RectangularPrismwidthheightdepth来定义此对象。你不能在那里null,因为否则它不会是一个矩形棱镜。

在这种情况下,我宁愿这样做:

public class RectangularPrism {
    private final Integer width;
    private final Integer height;
    private final Integer depth;    
    public RectangularPrism(Integer width, Integer height, Integer depth) {
      this.width = Objects.requireNonNull(width, "width");
      this.height = Objects.requireNonNull(height, "height");
      this.depth = Objects.requireNonNull(depth, "depth");
    }
    // getters    
}

或者使用setter:

public class RectangularPrism {
    public Integer width;
    public Integer height;
    public Integer depth;

    public void setWidth(Integer width) {
      this.width = Objects.requireNonNull(width, "width");      
    }
}

您不必处理null,因为JVM会抛出NullPointerException,但只有因为对象未完全/正确初始化,不是因为你没有处理不应该存在的null值。这是抛出IllegalStateException的正常行为,因为对象处于不应该处于的状态(此处:因为您有null个值)。

要完成,如果卷计算是RectangularPrism上的操作而不是外部操作,则会有更好的实现。

这种方式会更正确:

public class RectangularPrism {
    private final Integer width;
    private final Integer height;
    private final Integer depth;    
    public RectangularPrism(Integer width, Integer height, Integer depth) {
      this.width = Objects.requireNonNull(width, "width");
      this.height = Objects.requireNonNull(height, "height");
      this.depth = Objects.requireNonNull(depth, "depth");
    }
    public Integer computeVolume() {
      return width * height * depth; // can't be null.
    }
}

然后(我在那里使用int,因为有一个总和,我不会评论原语在包装类上的使用):

public Integer volumeSum(List<RectangularPrism> prismList) {
  int initial = 0;
  for (RectangularPrism p : prismList) 
    initial += p.computeVolume();
  return initial;
}

最后但并非最不重要的是,异常处理速度较慢,但​​循环中的异常处理速度较慢。