快捷搜索:  汽车  科技

程序员工作问题与解决(程序员的硬伤-异常管理)

程序员工作问题与解决(程序员的硬伤-异常管理)第一个问题是,为什么会发生异常?软件程序具有多个功能和子功能。每个函数按顺序执行,可以有输入和输出参数。通常,函数的输出成为另一个输入(图1-a)。在我们编写函数时,我们正在处理这些输入和输出变量。我们有意识或无意识地对这些变量做出一些假设。如果我们的假设有效,我们的代码就能很好地工作(图1-a)。如果某些事情与我们的假设相矛盾,那么我们的代码会出乎意料地行为(图1-b)。为了防止这些意外行为,我们通常会抛出异常。因此,良好的异常管理始于正确的假设。在本文中,我将编写几个异常处理的实践,如避免null值,编写可预测的函数签名,避免null引用异常等。return null; 或者:return 0; 或者:return -1; 在软件设计里,异常管理是必不可少的,也是软件开发中最重要的主题之一,而且是最被低估的主题之一。开发人员在开发业务需求时可能对日志记录和异常管理一无所知。因为,在正常

享学课堂作者:Peter

转载请声明出处!

本文试图来阐述一下程序中的异常处理实践,例如避免空值,编写可预测的函数签名,避免空引用异常等。

介绍

你是不是经常碰到NullReferenceException?而生产环境中一旦出现这情况,你是不是又花费很长时间,历经千辛万苦,才弄明白问题的根源在哪?像下面这样的代码,你是不是经常写:

return null;

或者:

return 0;

或者:

return -1;

在软件设计里,异常管理是必不可少的,也是软件开发中最重要的主题之一,而且是最被低估的主题之一。开发人员在开发业务需求时可能对日志记录和异常管理一无所知。因为,在正常情况下异常什么也不用做。另一方面,当生产环境中发生异常时,由于缺少日志记录和管理不善的异常,又会导致我们查找问题非常困难。

在本文中,我将编写几个异常处理的实践,如避免null值,编写可预测的函数签名,避免null引用异常等。

背景

第一个问题是,为什么会发生异常?软件程序具有多个功能和子功能。每个函数按顺序执行,可以有输入和输出参数。通常,函数的输出成为另一个输入(图1-a)。在我们编写函数时,我们正在处理这些输入和输出变量。我们有意识或无意识地对这些变量做出一些假设。如果我们的假设有效,我们的代码就能很好地工作(图1-a)。如果某些事情与我们的假设相矛盾,那么我们的代码会出乎意料地行为(图1-b)。为了防止这些意外行为,我们通常会抛出异常。因此,良好的异常管理始于正确的假设。

如何做出假设?

假设我们给出了一个包含以下两个函数的接口。这两个函数中的一个返回null (我们不知道哪个),而另一个函数在客户不存在的情况下抛出异常。

Customer GetCustomerByEmail(String email); Customer GetCustomerById(int customerId);

当我们像下面这样使用时:

Customer customer = customerProvider.GetCustomerByEmail(email); //Should I check null value? CallCustomer(customer.PhoneNumber);

我们应该在使用customer变量之前检查null值吗?即使我们知道这一点,我们也很容易忘记检查。我们也可能编写不必要的 - null检查块,它会使我们的代码变得混乱。

但是如果我们知道函数永远不会返回null值,那么我们就不必编写不必要的null-checking块。如下面这样

//A SaleOrder has always an existing customer. Customer customer = customerProvider.GetCustomerById(order.CustomerId);

客户在数据库中不存在的情况是意外行为。所以最好在这里抛出异常。不要忘记记录有用的信息或者自定义新的异常类。这样,使用者就不用关心空值的情况了。

public Customer GetCustomerById(int customerId){ Customer customer = db.GetCustomerById(customerId); if (customer == null) throw new EntityNotFoundException("Customer not found. CustomerId:" customerId); return customer; } 什么时候处理异常?

大部分情况下,我们不需要处理异常。但是,如果是在某些不重要或可选操作中发生异常,我们希望它不要影响主流程,向日志文件写入警告即可。此时,我们就需要捕获调用链的异常。

使用代码

为了演示上面的情况,我创建了一个示例应用程序。此示例应用程序包含非常简单的模型类,它们只包含我们将要使用的一些属性。

程序员工作问题与解决(程序员的硬伤-异常管理)(1)

项目中的其他文件/类:

  • DBConnection:返回预定义对象的数据库模拟类
  • EntityNotFoundException:自定义异常类
  • Example1,Example2,Example3:三个示例文件。详细信息如下
  • Program:申请的入口点。默认Main方法如下所示:

static void Main(string[] args) { try { RunExample1(); //RunExample2(); //RunExample3(); } catch (Exception ex) { LogEx(ex); } Console.ReadLine(); }

您可以运行其他示例。只需注释掉RunExample1()并取消注释其中一行。

例1

初步代码有不良做法。实际上,根本没有异常管理。当你运行时,你得到一个“ NullReferenceException”。您得不到任何关于该异常的线索。

程序员工作问题与解决(程序员的硬伤-异常管理)(2)

例2

好一点的示例。它会抛出异常或返回值的对象null。现在我们知道在加载City引用的时候发生了异常Address。但是我们仍然不知道哪个订单的地址有无效的City引用。

程序员工作问题与解决(程序员的硬伤-异常管理)(3)

示例3

在第三个例子中,我添加了异常处理块,编写了有用的信息并重新抛出了异常。现在我们知道order,address和city数据导致异常!

程序员工作问题与解决(程序员的硬伤-异常管理)(4)

结论

我解释了如何避免null引用,并编写可预测的方法签名,以帮助开发人员避免不必要的null检查块。希望对你有所帮助。

问题:空对象的返回,应该如何规避?

答:如果为空的情况发生,而此情况属于业务上的意外情况,应该为此情况抛出一个异常类,描述此情况信息。

你的赞和关注是我继续创作的动力~

猜您喜欢: