‫欢迎回来｡
‫在这段视频中, 我们将最终解决我们在程序中遇到的问题, 我们创建的虚拟程序｡
‫我们还将研究防御性编程｡
‫所以防御性编程的想法是让安全代码真正考虑到可能出现的问题, 因为在这种情况下, 可能出现的问题是, 例如,
‫列表是空的,
‫或者我们想有太多的朋友, 所以我们想邀请比我们更多的朋友｡
‫在这个例子中, 这个列表是我们手动创建的一个超级简单的列表｡
‫但想象一下它来自数据库｡
‫它来自数据库, 或者来自网络, 或者来自云数据库之类的东西｡
‫然后这将是一个超级不同的故事, 因为我们永远不会知道在这种情况下有多大的名单｡
‫我们可以在代码中看到它, 但我们可能不知道它, 这取决于它来自哪里｡
‫在这种情况下, 我们必须预测可能出现的不同问题, 并在开发时自己进行测试｡
‫例如, 我们已经这样做了, 对不对？
‫我们输入的朋友比列表中的更多｡
‫所以这是一个简单的问题｡
‫我们只需要运行这个程序, 然后我们得到这个参数超出范围异常｡
‫但我们得到它的地方是一个有趣的地方｡
‫所以我们是在get party的不同方法的点上得到它的, 即使问题出在别的地方｡
‫因为如果我们看一下, 它显示最短名字列表为零｡
‫所以我们试图访问一个列表元素, 它是不可用的, 因为我们已经通过了这个列表, get party friend,
‫然后我们把这个列表传递到这里｡
‫因此, 如果我们查看从何处获得此列表, 这可能是一个很好的起点, 因为我们可以在此处看到,
‫我们正在尝试访问不可用的内容｡
‫那么, 提供的东西有什么问题呢？
‫我们可以看看这条线, 得到党的朋友｡
‫这就是它的名字
‫而且我们可以看到｡
‫好了, 这是缓冲区｡
‫对不对？
‫我们得到一个缓冲区, 就是这个列表｡
‫所以我们得到的是一份最高层的名单｡
‫我们可以看到, 我们得到了一个列表, 上面有很多人,
‫这就是我们得到值的地方｡
‫好吧, 检查列表是否正确的一个好方法是在我们的“获取派对朋友”方法中, 因为这里我们得到了列表, 对吧｡
‫现在我们有了一个列表, 我们可以检查这个列表｡
‫我们可以看看这个列表对于我们想做的事情来说是否足够好｡
‫我们要做的就是根据列表中元素的数量写一些东西, 这样我们就可以检查计数是否大于列表点计数｡
‫这是我们收到的名单｡
‫如果是这样的话, 我们能做的就是打印一些东西, 不要这样做或错误或类似的事情｡
‫但我们能做的更好的事情是我们能让程序崩溃｡
‫所以我们知道程序有问题, 但同时, 我们在非常早的阶段就停止程序的执行, 因为假设我们有一个到数据库的连接,
‫现在我们正在创建所有这些不同的错误, 或者我们只是在浏览代码, 这个方法get
‫party friend正在运行, 让我们假设它'它连接到数据库,
‫并向数据库中写入一些内容, 然后我们再次运行代码｡
‫由于某种原因, 数据库状态发生了变化, 现在我们感到非常震惊, 因为显示给我们的数据完全是毫无意义的,
‫我们无法使用它｡
‫所以修复这个bug将是一个真实的问题｡
‫好吧, 我会的
‫所以我们已经可以尽早地捕捉到它了, 这样我们就可以在这里简单地抛出一个参数超出范围的异常｡
‫所以抛出新的参数超出范围异常因为这是我们得到的正确结果｡
‫而异常中的参数有多个重载｡
‫所以我们可以在这里使用param名称｡
‫我们可以有一个带有异常的消息, 也可以有一个带有消息的参数名｡
‫所以这里我可以说, 好吧, 计数是个问题,
‫计数不能大于列表中的元素｡
‫这是我们可以展示的一个例子｡
‫所以让我们再运行一次, 因为现在我们应该能够捕捉到这个错误, 或者至少在我们得到这个错误后,
‫抛出一个参数超出范围的异常｡
‫好吧, 我会的
‫所以我们可以看到异常在处理它时表示系统参数超出范围异常不能大于列表中元素的参数计数｡
‫这就是我们在这里所写的结果｡
‫这就是异常的样子｡
‫所以现在我们知道问题出在哪里了｡
‫这样更有表现力｡
‫就在问题并不存在之前｡
‫所以让我把这两行注释掉｡
‫问题并没有在这一点上抛出, 而是被抛到了更深的地方｡
‫它被扔在我们得到不同的方法｡
‫所以它在第42行｡
‫但实际问题出现得更早｡
‫好吧, 我知道了
‫并且索引超出范围异常｡
‫这也是一个非常通用的说法, 对吧｡
‫什么都有可能｡
‫好吧, 我知道了
‫因此, 及早发现它有助于我们发现问题所在｡
‫所以我们可以说, 好的, 一旦我们输入这个值,
‫假设这个值来自输入值的用户, 对吗？
‫因此, 您可以输入从零到列表元素数量之间的任何值｡
‫这样我们就能更早地发现它｡
‫我们甚至可以在这里做个测试｡
‫所以如果｡
‫朋友｡
‫点计数是｡
‫小于我们在此处输入的值, 我们可以再次从用户处获取此值｡
‫然后我们可以给予他们一个消息, 对不对？
‫我们不会掷回例外状况｡
‫我们就不会让程序崩溃｡
‫我们只要求用户输入一个新值｡
‫但我们在这里没有这样做, 因为作为程序员, 我们可以在这里输入值, 我们现在就手动强制这些错误｡
‫好吧, 我知道了
‫所以这是一种解决问题的方法, 或者说是一种早期发现问题的方法｡
‫现在, 让我们说｡
‫我们在这里输入了一个愚蠢的值, 比如-1｡
‫好吧, 现在我们再来一遍｡
‫实际上, 我们再运行一次｡
‫我们的程序看起来是有效的, 但它没有显示任何东西｡
‫所以它没有显示任何｡
‫错误没有抛出任何错误, 但它不显示任何朋友｡
‫我们的程序似乎可以处理-1, 因为我们试图从列表中得到-1列表元素,
‫但它并没有给予我们任何有价值的信息｡
‫当然, 现在我们可以在这里添加另一个条件｡
‫计数应大于等于零｡
‫如果不是这样, 我们可以写一些东西,
‫比如不能大于列表中的元素或小于零｡
‫这只是一种表达方式｡
‫现在, 如果我们再次运行它, 我们将抛出此错误｡
‫这是程序之前没有使用箭头的地方, 但现在作为开发人员, 我们明白了, 好吧,
‫这是我们不想拥有的状态｡
‫这种情况我们不想处理｡
‫就像我说的, 我们会很好地削减, 我们会试图从某个地方得到这个值, 我们会试图在那之前就抓住它｡
‫现在, 让我们假设我们有一个更有趣的情况｡
‫因此, 我们有一个情况, 我的朋友的名单是空的｡
‫所以我在这里创建一个空列表｡
‫比如, 现在这将被注释掉, 现在我们有了这个空列表｡
‫让我们再运行一次, 看看我们的程序是否仍然有效｡
‫现在我们仍然得到参数超出范围异常｡
‫所以这很酷｡
‫看起来我们在这里创建的异常甚至解决了这个问题, 所以我们不必手动查看列表是什么样的, 即使它是空的,
‫对吗？
‫所以如果我们看一下我们的好友列表, 我们的好友列表是空的, 但最后我们得到的计数是零｡
‫因此, 即使列表为空, 列表仍然为零｡
‫所以我们得到的值仍然是零｡
‫但这并不是我们实际上能强迫一个真正的空｡
‫所以我们可以在这里传递null, 而不是把France和France一起传递, 也就是这个空列表.
‫假设由于某种原因, 我们无法创建这个列表, 因为数据库连接不起作用,
‫或者类似的原因, 我们得到了一个空值, 现在我们传递空值,
‫我们试图将空值传递给一个实际上需要列表的方法｡
‫让我们运行它, 看看这次会出现什么样的错误｡
‫所以现在我们得到一个null引用异常对象引用没有设置为null的一个对象列表的实例｡
‫所以我们现在通过的名单是现在｡
‫所以我们甚至在抛出错误之前就得到了这个错误｡
‫所以我们能做的, 当然, 就是我们也能捕捉到这种情况｡
‫所以我们可以继续编写另一个if语句｡
‫如果list为空, 则抛出一个空指针｡
‫异常引发新参数｡
‫NULL异常错误｡
‫所以名单｡
‫列表为空｡
‫好吧, 我会的
‫当然, 你可以在这里更详细地描述, 而不是列表应该是空的｡
‫请检查网络连接或类似的东西｡
‫它可以是互联网连接或任何你从那里得到你的数据｡
‫我们再来一遍｡
‫而现在我们应该抛出我们现在的论证例外｡
‫可以看到, 该列表是空的参数列表｡
‫好极了｡
‫好吧, 我会的
‫现在, 你可能想知道, 我们为什么要做这一切？
‫我不希望我的程序总是崩溃｡
‫我们这样做是为了让程序不会进入实际上会更改数据库中某些内容的状态｡
‫我们不会改变数据库中的任何东西, 在我们的小程序中｡
‫但想象一下, 当时的情况会是这样｡
‫这是一个非常不同的情况, 我们可以在这里创造一些严重的问题｡
‫现在, 我想给你们看最后一件东西, 因为在我们拥有这一切之前, 对吗？
‫所以在我们有这个if语句和这个, 那个等等之前, 在我们有这个朋友列表之前｡
‫是的, 我可以停下来｡
‫之前我们在这里有朋友, 我们在那边也有朋友, 然后我们试着在派对上有十个朋友,
‫但我们只有七个朋友.
‫在这种情况下, 一旦我们运行了这个程序, 我们就可以强制执行这个错误, 这个错误是在get party friend中发生的｡
‫所以我们得到这个参数超出范围, 异常索引超出范围｡
‫这是我们在修复之前遇到的问题｡
‫好吧, 我知道了
‫但现在我们可以看到的有趣的事情是调用栈｡
‫所以有一种叫做调用栈的东西｡
‫让我把这里放大一点｡
‫事实上, 让我把这些都关上｡
‫现在我们来看看这个调用堆栈｡
‫这里的调用栈显示我们当前在第46行｡
‫好吧, 我会的
‫我们就在那里｡
‫所以我们是在找方友法｡
‫现在, 如果我们再往上走一步, 我们可以看到这是在哪里得到党的朋友方法被调用｡
‫现在我们来看看里面的获取方友复数的方法｡
‫如果你想知道这个方法是在哪里被调用的呢？
‫第13行被叫到了｡
‫因此, 通过调用堆栈, 我们可以看到从哪里调用我们, 从哪里再次调用我们, 等等｡
‫所以我们可以一路向上到初始方法的调用层次｡
‫而最初的方法是得到党的朋友被调用｡
‫然后我们进入这个疯狂的循环, 然后调用get party friend,
‫然后我们进入这个方法, 最后我们的变量是基于一个空列表创建的.
‫好了, 我希望这能让你对调试有一点了解｡
‫当然, 还有很多东西需要了解,
‫但我不想用所有的细节来烦你, 因为有些东西是有用的, 但其中许多东西在你的日常生活中并不需要｡
‫因为, 我的意思是, 一般来说,
‫你当然可以继续进行调试, 然后检查所有不同的窗口,
‫你可以看到正在运行的线程和并行进程等｡
‫但我认为, 你们现在看到的将是主要的东西, 或者说, 将是你们将需要的主要东西,
‫你们将需要的主要工具, 以便调试你们的软件｡
‫好吧, 我会的
‫我希望你们喜欢这本书, 也希望你们能在未来的课程中利用这本书｡
‫现在您终于可以看到调试是如何解决的了｡
‫顺便说一句, 谢谢你给我这个反馈, 因为我得到的反馈是, 缺少了一个调试部分,
‫所以我决定创建这个小部分｡
‫所以非常感谢你的反馈｡
‫如果您认为本课程缺少什么, 或者您认为有些地方非常糟糕,
‫请不要直接给予我一个差评, 但请让我知道是什么, 这样我就可以改进课程,
‫因为我的目标是使本课程成为市场上最好的C升课程｡
‫所以非常感谢你的帮助, 我希望在下一个视频中看到你｡