一尘不染

使用try / catch防止应用崩溃

java

我一直在开发一个Android应用程序,该应用程序try/catch经常使用以防止它崩溃,即使在不需要的地方也是如此。例如,

在视图xml layoutid = toolbar被引用,如:

// see new example below, this one is just confusing
// it seems like I am asking about empty try/catch
try {
    View view = findViewById(R.id.toolbar);
}
catch(Exception e) {
}

在整个应用程序中都使用这种方法。堆栈跟踪没有打印出来,很难找到问题所在。该应用程序突然关闭而不打印任何堆栈跟踪。

我请我的长辈向我解释一下,他说:

这是为了防止生产崩溃。

我完全不同意 。对我来说,这不是防止应用程序崩溃的方法。它表明开发人员 知道自己在做什么,并且对此表示怀疑。

这是行业中用来防止企业应用程序崩溃的方法吗?

如果try/catch确实是,这确实是我们的需要,那么是否可以将异常处理程序与UI线程或其他线程连接,并在那里捕获所有内容?如果可能的话,那将是一个更好的方法。

是的,为空try/catch很不好,即使我们将堆栈跟踪或日志异常打印到服务器,try/catch对我来说,将代码块随机地包装在所有应用程序中也无济于事,例如,每个函数都包含在中try/catch

更新

由于这个问题引起了广泛关注,并且有些人误解了这个问题(也许是因为我没有清楚地表述),所以我将其重新表述。

这是开发人员在这里所做的

  • 一个函数是 经过 编写和 测试的 ,它可以是一个仅初始化视图的小函数,也可以是一个复杂的函数,在测试后将其包裹在try/catch块中。即使对于永远不会抛出任何异常的函数。

  • 在整个应用程序中都使用了这种做法。有时打印堆栈跟踪,有时只是打印debug log一些随机错误消息。此错误消息因开发人员而异。

  • 通过这种方法,应用程序不会崩溃,但是应用程序的行为不确定。即使在某个时候,也很难跟踪出了什么问题。

  • 我一直在问的真正问题是; 业界是否正在遵循这种惯例来防止企业应用程序崩溃? 而且我不是在问 空try / catch 。就像用户喜欢不会崩溃的应用程序比行为异常的应用程序吗?因为它实际上归结为要么崩溃,要么为用户呈现空白屏幕,或者用户不知道该行为。

  • 我在这里从真实代码中发布了一些代码片段

          private void makeRequestForForgetPassword() {
        try {
            HashMap<String, Object> params = new HashMap<>();

            String email= CurrentUserData.msisdn;
            params.put("email", "blabla");
            params.put("new_password", password);

            NetworkProcess networkProcessForgetStep = new NetworkProcess(
                serviceCallListenerForgotPasswordStep, ForgotPassword.this);
            networkProcessForgetStep.serviceProcessing(params, 
                Constants.API_FORGOT_PASSWORD);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

     private void languagePopUpDialog(View view) {
        try {
            PopupWindow popupwindow_obj = popupDisplay();
            popupwindow_obj.showAsDropDown(view, -50, 0);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    void reloadActivity() {
        try {
            onCreateProcess();
        } catch (Exception e) {
        }
    }

这是
重复的Android的异常处理的最佳实践,有OP试图捕获异常为 不同 的目的不是这个问题。


阅读 691

收藏
2020-12-03

共1个答案

一尘不染

当然,规则总是有例外,但是如果您需要经验法则,那么您是正确的。空捕获块是“绝对”的坏习惯。

让我们仔细看看,首先从您的特定示例开始:

try {
  View view = findViewById(R.id.toolbar);
}
catch(Exception e) { }

因此,创建了对某事物的引用。当失败的时候…没关系;因为首先没有使用该引用!上面的代码绝对是 无用的线路噪音
。还是编写该代码的人最初假设第二个类似的调用将不再神奇地抛出异常?

也许这看起来像:

try {
  View view = findViewById(R.id.toolbar);
  ... and now do something with that view variable ...
}
catch(Exception e) { }

但是,这又有什么帮助呢?存在异常,以在您的代码中 传达 相应的 传播 错误情况。忽略错误很少是一个好主意。实际上,可以按以下方式处理异常:

  • 您向用户提供反馈;(例如:“您输入的值不是字符串,请重试”);或从事更复杂的错误处理
  • 也许问题是某种可以预料到的,并且可以缓解(例如,当某些“远程搜索”失败时,通过给出“默认”答案)

长话短说:您对异常的 最小处理 是对其进行记录/跟踪。因此,当您以后进行调试时,您会理解“确定,这时发生了异常”。

正如其他人指出的那样:您通常也避免捕获 Exception (嗯,取决于层:可能有充分的理由对 Exception进行
捕获,甚至在最高级别捕获某些错误,以确保 没有 迷路, 永远 )。

最后,引用沃德·坎宁安(Ward Cunningham):

您知道当您阅读的每个例程几乎都符合您的预期时,您正在使用干净的代码。 当代码也使它看起来像是针对问题而设计的语言时,可以将其称为精美代码。

让它沉入其中并进行冥想。干净的代码并 不会 令你大吃一惊。您向我们展示的示例让 每个人都 惊讶。

更新 ,关于OP要求的更新

try {
  do something
}
catch(Exception e) { 
  print stacktrace
}

同样的答案:“到处都是”也是 不好的 做法。因为此代码 使读者感到惊讶。

以上:

  • 在某处打印错误信息。完全 不能 保证此“某处”类似于 合理的 目的地。与此相反的。示例:在我正在使用的应用程序中,此类调用会神奇地出现在我们的跟踪缓冲区中。根据具体情况,有时我们的应用程序可能会向这些缓冲区中注入大量数据。每隔几秒钟进行一次缓冲修剪。因此,“仅打印错误”通常会翻译为:“仅丢失所有此类错误信息”。
  • 然后:您不可以尝试/捕获,因为 可以 。之所以这样做,是因为您了解自己的代码在做什么;而且您知道:我最好在这里尝试一下/做对的事情(再次参见答案的第一部分)。

因此,将try / catch用作显示的“模式”;就像这样说:仍然不是一个好主意。是的,它 可以防止
崩溃;但会导致各种“未定义”行为。您知道,当您只是捕获异常而不是 适当地 处理它时;你打开一罐蠕虫;因为您可能会遇到无数 后续
错误,这些错误后来您都无法理解。因为您之前消耗了“根本原因”事件;印在某处 那个 地方 现在不见了。

2020-12-03