0

我有一个永远不会返回的 Android 错误处理程序(它记录一条消息并引发错误异常)。如果我从通常返回值的方法调用错误处理程序,Android Studio lint 检查器会报告错误,因为没有返回值。有没有办法告诉 Android Studio 我的错误处理程序没有返回,或者在调用它之后代码中的点实际上是无法访问的。

当然,我可以放入一个不必要的 return 语句,返回一个正确类型的虚拟值,但这是不雅的,并且用无法访问的语句使我的应用程序混乱。

我找不到要禁用的代码检查以防止错误,但即使有一个要禁用,也会阻止它报告真正缺少的返回语句。

再说一遍,这不是Java 语法问题。人们说过,Java 方法必须返回声明类型的值。这是
(a)不相关的
(b)不正确的。
正确的说法是,如果 Java 方法返回,则必须返回声明类型的值。这段代码

public long getUnsignedLong(String columnName)
    throws NumberFormatException, NoColumnException
{
    String s = getString(columnName, "getUnsignedLong");
    if ((s != null) && s.matches("^[0-9]+$")) {
        return Long.parseLong(s);
    }
    else
    {
        throw(new NumberFormatException("Bad number " + s));
    }
}

是完全有效的 Java,AS 不会抱怨它。return确实,如果我像这样插入不必要的

public long getUnsignedLong(String columnName)
    throws NumberFormatException, NoColumnException
{
    String s = getString(columnName, "getUnsignedLong");
    if ((s != null) && s.matches("^[0-9]+$")) {
        return Long.parseLong(s);
    }
    else
    {
        throw(new NumberFormatException("Bad number " + s));
    }
    return 0;
}

AS 抱怨它无法访问。

我抛出异常的问题是,如果它真的发生了,我的应用程序的用户看到的是一个弹出窗口,提示应用程序已停止并询问用户是否要禁用它。这对用户不是很有帮助,当用户向我报告它已经发生时,对我也不是很有帮助。因此,我没有抛出异常,而是调用了我的致命错误处理程序,如下所示:-

// Always invoked with fatal = true
// Report a fatal error.
// We send a message to the log file (if logging is enabled).
// If this thread is the UI thread, we display a Toast:
// otherwise we show a notification.
// Then we throw an Error exception which will cause Android to
// terminate the thread and display a (not so helpful) message.
public MyLog(Context context, boolean fatal, String small, String big) {
    new Notifier(context, small, big);
    new MyLog(context, big, false);
    throw(new Error());
}

是的,我知道这个参数fatal没有被引用,但是它的存在安排了我的错误处理程序的这个特殊重载被调用,你可以看到它抛出一个异常并且不返回。

我的实际问题是,如果我通过调用不返回的致命错误处理程序来替换throwin ,则 AS 在结束时抱怨它返回时没有值。好吧,这是错误的:这一点与以前一样不可触及。我尝试在说它总是失败之前放置一个合同,但这没有帮助,并且在 AS 错误报告中按右箭头并没有提供任何抑制它的方法。我可以输入一个 dummy statement 或一个 dummy ,但其中任何一个实际上都是无法访问的代码,我认为这是不优雅和不必要的。getUnsignedLonggetUnsignedLongMyLogreturnthrow

所以我的问题与最初提出的问题一样:我如何告诉 Android Studio 一个方法没有返回?

4

3 回答 3

0

您的问题似乎是 Java 问题。

在 Java 中,非 void 方法必须返回它应该返回的类型。在你的情况下是一样的。

所以简单的解决方案是返回一个虚拟值。这是为了编译器。

最好的(更难的)解决方案是避免这种结构。如果一个方法正常返回一个值,该方法就会有返回值,如果出现错误,就会发生异常。错误处理程序应该处理错误,这意味着它不是默认行为。

此外,您可能想看看这里:unreachable-code-error-vs-dead-code-warning-in-java

如果您担心单元测试覆盖率。当你进行单元测试时,总有一些你无法触及的代码部分。这就是为什么我们几乎从不希望覆盖 100 的原因之一

于 2019-12-25T08:22:22.687 回答
0

方法基本上是您希望以不同方式访问的代码(在一行中调用一个方法比代码> 50行等更容易)。创建方法时,您可以调用它:

“void”(从不返回值),

“字符串”(返回一组字符/字母),

“int”(返回其范围内的数字。整数类型),

“boolean”(返回 2 类型的值,true 或 false)。

和更多...

在这些方法中,你可以做任何你想做的事情,但要确保它们最终返回初始化中指定的值类型。

例子:

int y = 2;

boolean booleanMethod(){
  y = 6;
  return true; //or false, doesn't really matter in this case.
}

boolean trueOrFalse(){
  if (y == 2) return true;
  else return false;
}

//or

void method(int nr){
  nr = 10;
}

这些只是 Java* 中方法的一些基本示例,因为您的问题是语法问题,而不是真正的 AS 问题。

于 2020-01-01T00:15:26.287 回答
0

AS 抱怨它无法访问。

Android Studio 是正确的。Android Studio正确实现了 Java 语言规范中的可达性规则。

这是一个 Java 语义问题。(这不是语法问题,但不要分叉。)

让我们创建一个简单但完整的示例来说明为什么Android Studio 是正确的:

public class Test {
    public int method1() throws Exception {
        int result;
        method2();
        return result;
    }
    
    public boolean method2() throws Exception {
        throw new Exception("bad stuff");
    }
}

$ javac Test.java 
  Test.java:5: error: variable result might not have been initialized
              return result;
                     ^
  1 error

(我手头没有 Android Studio 的副本,但这会给 . 带来类似的编译错误javac。试试吧。)

为什么这是一个错误?毕竟,根据您的推理,该return语句应该是不可访问的。

这就是问题所在。JLS 不是这么说的。事实上,JLS 14.21除其他外还说了以下内容。(这些陈述是摘录,为了清楚起见,我添加了数字。“iff”是 JLS 用于“当且仅当”的缩写。)

  1. “作为构造函数、方法、实例初始化程序或静态初始化程序主体的块是可访问的。”

  2. “如果块可访问,则非空块中不是 switch 块的第一条语句是可访问的。”

  3. “一个局部变量声明语句可以正常完成,如果它是可访问的。”

  4. “如果 S 之前的语句可以正常完成,则非空块中不是 switch 块的所有其他语句 S 都是可访问的。”

  5. “一个表达式语句可以正常完成,只要它是可达的。”

考虑method1.

  • 通过 #1 - 块是可达的
  • 通过#2 - 的声明result是可达的。
  • 通过#3 - 声明可以正常完成
  • 通过 #4 -method2()可以访问
  • 通过#5 - 调用可以正常返回
  • 通过#4 - 该return语句是可达的。

但也很清楚,如果我们到达了return语句,那么result肯定不会被初始化。(这显然是真的。JLS 16证明了这一点。)


好的,那么为什么他们以这种方式指定 Java?

在一般情况下,method1并且method2可以在单独的编译单元中;例如案例AB。这意味着这些方法可以在不同的时间编译,并且只在运行时组合在一起。现在,如果编译器需要分析 in 的主体B.method2以确定returninA.method1是否可访问,那么考虑以下情况会发生什么:

  • 的代码在编译后被B.method2修改和B重新编译A,或者
  • 加载了一个子类C,在该子类中正常返回。BC.method2

简而言之,如果我们method2在分析可达性时需要考虑内部的流程method,我们无法在编译时得出答案。


结论:

  1. JLS 清楚地说 / 意味着(我的)示例程序是错误的。
  2. 这不是规格错误。
  3. 如果 Android Studio(或javac没有错误地调用示例,那么它就不是Java 的有效实现。
于 2020-03-09T12:21:23.323 回答