为什么要避免使用异常来控制Java流

Java是一种通用编程语言,为您的特定任务提供了许多替代解决方案。 尽管如此,还是应该遵循好的方法,而且在大多数情况下,我们仍然会使用一些不成功的方法。

最常见的失败方法之一是使用异常来控制执行流程。 应该避免这种情况有两个原因:

  1. 这会降低代码的性能和速度。
  2. 这会使您的代码可读性降低。

让我们从一个例子开始。 在这里,异常用于控制执行流程:

public static int findAge(String name) { try { String ageAsString = findUser(name); return ageAsString.length(); } catch (NameNotFoundException e) { return 0; } } private static String findUser(String name) { if(name==null) { throw new NameNotFoundException(); } return name; } 

如果用户提供名称的非null值,则findAge方法将返回此名称的长度,但是如果用户名为null,则findUser方法将引发NameNotFoundException异常,在这种情况下,findAge方法将返回0。

我们如何在不使用异常的情况下转换此代码? 通常,有很多选择,请考虑其中一种:

 public static int findAgeNoEx(String name) { String ageAsString = findUserNoEx(name); return ageAsString.length(); } private static String findUserNoEx(String name) { if(name==null) { return ""; } return name; } 

为了找出异常对性能的影响,我准备了以下代码,该方法调用这两种方法的1000万次:有和没有异常。

 public class ControlFlowWithExceptionOrNot { public static class NameNotFoundException extends RuntimeException { private static final long serialVersionUID = 3L; } private static final int TRIAL = 10000000; public static void main(String[] args) throws InterruptedException { long start = System.currentTimeMillis(); for (int i = 0; i < TRIAL; i++) { findAgeNoEx(null); } System.out.println("Duration :" + (System.currentTimeMillis() - start)); long start2 = System.currentTimeMillis(); for (int i = 0; i < TRIAL; i++) { findAge(null); } System.out.println("Duration :" + (System.currentTimeMillis() - start2)); }; public static int findAge(String name) { try { String ageAsString = findUser(name); return ageAsString.length(); } catch (NameNotFoundException e) { return 0; } } private static String findUser(String name) { if (name == null) { throw new NameNotFoundException(); } return name; } public static int findAgeNoEx(String name) { String ageAsString = findUserNoEx(name); return ageAsString.length(); } private static String findUserNoEx(String name) { if (name == null) { return ""; } return name; } } 

结论:

 Duration :16 Duration :6212 

如您所见,在我的英特尔酷睿i7-3630QM上使用异常花费了数千毫秒。

如果我们在可读性方面比较两个findAge方法,则该方法毫无例外是绝对清楚的:首先,我们可以绝对确定findUser方法返回一个字符串; 其次,无论返回哪个字符串,我们都将获得其长度。 同时,带有该异常的方法有些令人困惑:尚不能完全清楚findUser方法返回什么。 它可以返回一个字符串,也可以引发异常,这在方法签名中是不可见的。 因此,函数式编程范例不欢迎使用异常。

最后,如果您确实要使用例外并且确实需要例外,那么最好使用例外。 如果使用异常来控制执行流程,则将导致程序性能下降,并使代码的可读性降低。

我希望本文对您来说很有趣,并且可能有用。

Source: https://habr.com/ru/post/zh-CN476142/


All Articles