安卓& Kotlin Books Kotlin学徒

20
例外 由伊琳娜加拉塔撰写

人们与软件作为开发人员和用户互动,有时他们会犯错误。例如,用户可以输入无效数据,并且开发人员可以忘记验证它。重要的是要注意和处理代码中的缺陷和潜在的弱点,以避免您的应用程序的不可预测行为以及对其用户不满意的经验。

例外 是检测软件中错误的便捷方式。这个概念用于各种各样的编程语言,包括Kotlin。

什么例外?

An exception is primarily an event which signals that something went wrong during program execution. Exceptions are represented by the Exception Java class, which is a superclass of all exceptions in Java and Kotlin programs — e.g., NullPointerException, IOException, etc. Depending on their nature, these events should be 捕捉 在运行时或固定以防止异常在第一位置发生。我会讨论本章后面的捕捉例外

相反,另一种类型的关键事件,一个 错误 — represented by Error 和 its subclasses — should not be handled but should instead be fixed, because it’s the result of serious problems in a program, like inappropriate memory usage, for example.

Both ExceptionError extend Throwable and, therefore, could be 抛出 by the JVM or manually from code using the keyword throw, in order to notify the user of the code that a problem occurred. Every Throwable object can contain a message and a cause — another Throwable instance that caused this error or exception, and a 堆栈跟踪 .

Let’s see how a program behaves when an exception occurs and you don’t handle it. Imagine a main() function that calls someFunction(), which calls anotherFunction(), which in turn calls oneMoreFunction() that throws an exception with the message “Some exception”.

Your program can be represented as a long chain of function invocations. When something goes wrong somewhere in oneMoreFunction(), an exception gets thrown and the normal execution flow interrupts.

该程序开始向前卷起以前的函数返回到另一行,从调用下一个函数,搜索此异常的处理程序。

Without handling the exception, the process ends up in the entry point of your app — the main() function — and then the app crashes, your user sees an annoying error message.

您将在终端中看到此异常的堆栈堆栈:

A 堆栈跟踪 是对程序中发生的例外的详细描述。它由涉及异常涉及的函数调用列表,按调用顺序和从调用它们的文件的行号。堆栈器有助于您找到发生异常的确切位置。

要防止应用程序崩溃,您应该 处理 例外;您可以在链中的任何功能中这样做,导致异常。现在,如果处理例外,请查看事情的变化:

While rolling up your program, it finds a handler inside someFunction() and, after handling an alternate execution, the program flow re-starts and your app doesn’t crash.

对于以下项目,您将使用异常来解决发布问题,机械故障和与外星人遇到!

投掷例外

让我们想象一下您是一个航天器工程师,主要责任是推动一个用于调查深层空间的工艺。空间启动过程可以通过不可预测的错误中断,就像程序执行一样。

class SpaceCraft {

  private var isConnectionAvailable: Boolean = false
  private var isEngineInOrder: Boolean = false
  private var fuel: Int = 0
  var isInSpace: Boolean = false

  fun launch() {
    if (fuel < 5) {
      sendMessageToEarth("Out of fuel. Can't take off")
      return
    }

    if (!isEngineInOrder) {
      sendMessageToEarth("The engine is broken. Can't take off")
      return
    }

    if (!isConnectionAvailable) {
      sendMessageToEarth("No connection with Earth. Can't take off")
      return
    }

    sendMessageToEarth("Trying to launch...")
    fuel -= 5
    sendMessageToEarth("I'm in space!")
    sendMessageToEarth("I've found some extraterrestrials")
    isInSpace = true
  }

  fun sendMessageToEarth(message: String) {
    println("Spacecraft to Earth: $message")
  }
}
object SpacePort {
  fun investigateSpace(spaceCraft: SpaceCraft) {
    spaceCraft.launch()
  }
}
fun main(args: Array<String>) {
  val spaceCraft = SpaceCraft()
  SpacePort.investigateSpace(spaceCraft)
}
Spacecraft to Earth: Out of fuel. Can't take off.
fun launch() {
  if (fuel < 5) {
    throw Exception("Out of fuel. Can't take off.")
  }

  if (!isEngineInOrder) {
    throw Exception("The engine is broken. Can't take off.")
  }

  if (!isConnectionAvailable) {
    throw Exception("No connection with Earth. Can't take off.")
  }
...
}

处理例外

当您抛出异常时,只要您可以从它们恢复,您应该处理它们。您没有义务处理您抛出它们的位置 - 您可以在堆栈堆栈上的任何级别进行操作。

fun investigateSpace(spaceCraft: SpaceCraft) {
  try {
    spaceCraft.launch()
  } catch (exception: Exception) {
    spaceCraft.sendMessageToEarth(exception.localizedMessage)
  }
}

创建自定义例外

You already know that every child of Exception is an exception, too. Therefore, you just need to create subclasses of Exception:

class OutOfFuelException :
        Exception("Out of fuel. Can't take off.")
class BrokenEngineException :
        Exception("The engine is broken. Can't take off.")
class SpaceToEarthConnectionFailedException :
        Exception("No connection with Earth. Can't take off.")
fun launch() {
  if (fuel < 5) {
    throw OutOfFuelException()
  }

  if (!isEngineInOrder) {
    throw BrokenEngineException()
  }

  if (!isConnectionAvailable) {
    throw SpaceToEarthConnectionFailedException()
  }
...
}
fun investigateSpace(spaceCraft: SpaceCraft) {
  try {
    spaceCraft.launch()
  } catch (exception: OutOfFuelException) {
    spaceCraft.sendMessageToEarth(exception.localizedMessage)
  } catch (exception: BrokenEngineException) {
    spaceCraft.sendMessageToEarth(exception.localizedMessage)
  } catch (exception: SpaceToEarthConnectionFailedException) {
    spaceCraft.sendMessageToEarth(exception.localizedMessage)
  }
}
fun refuel() {
  fuel += 5
  sendMessageToEarth("The fuel tank is filled.")
}

fun repairEngine() {
  isEngineInOrder = true
  sendMessageToEarth("The engine is in order.")
}

fun fixConnection() {
  isConnectionAvailable = true
  sendMessageToEarth("Hello Earth! Can you hear me?")
  sendMessageToEarth("Connection is established.")
}

fun land() {
  sendMessageToEarth("Landing...")
  isInSpace = false
}
fun investigateSpace(spaceCraft: SpaceCraft) {
  try {
    spaceCraft.launch()
  } catch (exception: OutOfFuelException) {
    spaceCraft.sendMessageToEarth(exception.localizedMessage)
    spaceCraft.refuel()
  } catch (exception: BrokenEngineException) {
    spaceCraft.sendMessageToEarth(exception.localizedMessage)
    spaceCraft.repairEngine()
  } catch (exception: SpaceToEarthConnectionFailedException) {
    spaceCraft.sendMessageToEarth(exception.localizedMessage)
    spaceCraft.fixConnection()
  } finally {
    if (spaceCraft.isInSpace) {
      spaceCraft.land()
    } else {
      investigateSpace(spaceCraft)
    }
  }
}

Java和Kotlin异常之间的区别

检查例外

如果您熟悉Java,您可能会记得有两种类型的例外 - 检查一下 未经选中 . Checked exceptions must be either handled or declared after your method signature with the throws keyword. Unchecked exceptions can be ignored, but then crash your app when not handled. Conversely, all exceptions in Kotlin are unchecked and, therefore, you’re not forced to handle them or declare them. Your program still terminates when exceptions get thrown.

try as an expression

In Kotlin, the try-catch construction is an expression. This means that you can get a value from a try-catch block and can equate it to some variable:

val date: Date = try {
    Date(userInput) // try to parse user input
  } catch (exception: IllegalArgumentException) {
    Date() // otherwise use current date
  }
}

挑战

关键点

  • 例外 是在程序中出现问题时发生的事件。
  • Extend the Exception class or its subclasses to create custom exceptions.
  • Throw an exception using the throw keyword.
  • Do not catch the base class Exception, use the most specific exception class you can.
  • 为罕见案例创建自定义例外以区分它们。
  • When handling exceptions, place the code that should be executed whether an exception occurs or not in the finally block.
  • Kotlin的所有例外都是 未经选中 .
  • 不要忽视例外。
  • 试试捕获是一种表达式。

然后去哪儿?

例外抛掷和处理可以是一点艺术。当您开发越来越多的应用程序时,您将熟悉异常时可能发生异常以及如何最好地处理它们。

有一个技术问题?想报告一个错误吗? 您可以向官方书籍论坛中的书籍作者提出问题和报告错误 这里 .

有反馈分享在线阅读体验吗? 如果您有关于UI,UX,突出显示或我们在线阅读器的其他功能的反馈,您可以将其发送到设计团队,其中表格如下所示:

© 2021 Razeware LLC

您可以免费读取,本章的部分显示为 混淆了 文本。解锁这本书,以及我们整个书籍和视频目录,带有Raywenderlich.com的专业订阅。

现在解锁

要突出或记笔记,您需要在订阅中拥有这本书或自行购买。