简体   繁体   English

如何告诉 Android Studio 方法不返回

[英]How to tell Android studio that a method does not return

I have an Android error handler which never returns (it logs a message and throws an error exception).我有一个从不返回的 Android 错误处理程序(它记录一条消息并抛出一个错误异常)。 If I call my error handler from a method which normally returns a value, the Android Studio lint checker reports an error because no value is returned.如果我从通常返回一个值的方法调用我的错误处理程序,Android Studio lint 检查器会报告一个错误,因为没有返回任何值。 Is there a way either to tell Android Studio either that my error handler does not return or that the point in the code after calling it is in fact unreachable.有没有办法告诉 Android Studio 我的错误处理程序没有返回,或者调用它后代码中的点实际上无法访问。

Of course I could put in an unnecessary return statement returning a dummy value of the correct type, but this is inelegant and clutters up my app with an unreachable statement.当然,我可以放入一个不必要的 return 语句,返回一个正确类型的虚拟值,但这是不雅的,并且用无法访问的语句使我的应用程序混乱。

I can't find a code inspection to disable to prevent the error, but even if there is one to disable, that would stop it reporting really missing return statements.我找不到要禁用的代码检查来防止错误,但即使有一个要禁用,也会阻止它报告真正丢失的返回语句。

Just to repeat, this is not a Java syntax issue.重复一遍,这不是Java 语法问题。 People have said that a Java method must return a value of the type declared.人们曾说过,Java 方法必须返回声明类型的值。 This is这是
(a) not relevant (a) 不相关
(b) not true. (b) 不正确。
The correct statement is that a Java method, if it returns , must return a value of the declared type.正确的说法是,Java 方法如果返回,则必须返回声明类型的值。 This bit of code这段代码

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));
    }
}

is perfectly valid Java, and AS does not complain about it.是完全有效的 Java,AS 不会抱怨它。 Indeed if I insert an unnecessary return like this事实上,如果我像这样插入一个不必要的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 complains that it is unreachable. AS 抱怨它无法访问。

My problem with throwing the exception is that if it actually happens, what my app's user sees is a popup window saying that the app has stopped and asking the user if they want to disable it.我抛出异常的问题是,如果它真的发生了,我的应用程序的用户看到的是一个弹出窗口,说应用程序已停止并询问用户是否要禁用它。 This isn't very helpful to the user and isn't very helpful to me when the user reports back to me that it has happened.这对用户不是很有帮助,并且当用户向我报告它已经发生时对我也不是很有帮助。 So instead of throwing the exception I call my fatal error handler which looks like this:-因此,我没有抛出异常,而是调用我的致命错误处理程序,如下所示:-

// 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());
}

Yes, I know that argument fatal isn't referenced, but its presence arranges that this particular overload of my error handler is called, and you can see that it throws an exception and doesn't return.是的,我知道没有引用fatal参数,但是它的存在安排了我的错误处理程序的这个特定重载被调用,并且您可以看到它抛出异常并且不返回。

My actual problem is that if I replace the throw in getUnsignedLong by a call to my fatal error handler, which doesn't return, AS complains at the end of getUnsignedLong that it is returning without a value.我的实际问题是,如果我通过调用我的致命错误处理程序而不返回来替换getUnsignedLongthrow ,AS 在getUnsignedLong结束时会getUnsignedLong它返回没有值。 Well, it's wrong : this point is just as unreachable as it was before.好吧,这是错误的:这一点和以前一样无法达到。 I tried putting a contract in front of MyLog saying that it always fails, but this doesn't help, and pressing right arrow at the AS error report doesn't offer any way of suppressing it.我尝试在MyLog前面放置一个合同,说它总是失败,但这无济于事,并且在 AS 错误报告中按向右箭头并没有提供任何抑制它的方法。 I could put in a dummy return statement or a dummy throw , but either of these would in fact be unreachable code, and I regard this as inelegant and unnecessary.我可以放入一个虚拟的return语句或一个虚拟的throw ,但其中任何一个实际上都是无法访问的代码,我认为这是不雅的和不必要的。

So my question stands as it was originally asked: how do I tell Android Studio that a method does not return?所以我的问题就像最初被问到的那样:我如何告诉 Android Studio 一个方法没有返回?

Your problem seems to be a Java problem.您的问题似乎是 Java 问题。

In Java a non-void method must return the type it should return.在 Java 中,非 void 方法必须返回它应该返回的类型。 In your case it's the same.在你的情况下是一样的。

So the simple solution would be to return a dummy value.所以简单的解决方案是返回一个虚拟值。 It's for the sake of the compiler.这是为了编译器。

The best (harder) solution is to avoid having that kind of construction.最好(更难)的解决方案是避免使用这种结构。 If a method normally returns a value, the method will have a return, and in case of an error an exception can occurs.如果一个方法通常返回一个值,该方法将有一个返回值,并且在出现错误的情况下可能会发生异常。 An error handler should handle an error, which means that it's not the default behavior.错误处理程序应该处理错误,这意味着它不是默认行为。

Also, you may want to have a look here: unreachable-code-error-vs-dead-code-warning-in-java另外,您可能想看看这里:unreachable-code-error-vs-dead-code-warning-in-java

If you worry about unit test coverage.如果您担心单元测试覆盖率。 When you do unit test, there is always some parts of the code that you can't reach.当您进行单元测试时,总会有一些您无法触及的代码部分。 That's one of the reason why we almost never want a coverage of 100这就是为什么我们几乎从不想要覆盖 100

A method is basically code that you want to access in different ways (easier to call one method in a line than code >50 lines, etc.).方法基本上是您想要以不同方式访问的代码(在一行中调用一个方法比代码 > 50 行更容易,等等)。 When you create the method you either call it:创建方法时,您可以调用它:

"void" (never returns an value), “void” (从不返回值),

"String" (returns a set of characters/letters), “字符串” (返回一组字符/字母),

"int" (returns a number within it's bounds. Integer Types ), “int” (返回范围内的数字。 整数类型),

"boolean" (returns a 2-type value, true or false). “boolean” (返回 2 型值,真或假)。

And more...和更多...

In those methods you cand do whatever you want, but make sure that in the end they return the value type specified in the initialization.在这些方法中,您可以随心所欲,但请确保它们最终返回初始化中指定的值类型。

Example:例子:

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;
}

Those are just some basic examples of methods in Java*, because your problem was a syntax one, not really an AS one.这些只是 Java* 中方法的一些基本示例,因为您的问题是语法问题,而不是真正的 AS 问题。

AS complains that it is unreachable. AS 抱怨它无法访问。

Android Studio is correct. Android Studio 是正确的。 Android Studio is correctly implementing the reachability rules in the Java Language Specification. Android Studio正确实现了 Java 语言规范中的可达性规则。

This is a Java semantics issue.这是一个 Java 语义问题。 (It is not a syntax issue, but lets not split hairs.) (这不是语法问题,但不要分心。)

Lets create a simple but complete example to illustrate why Android Studio is correct:让我们创建一个简单但完整的示例来说明为什么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

(I don't have a copy of Android Studio to hand, but that would give a similar compilation error to javac . Try it.) (我手头没有 Android Studio 的副本,但这会给javac带来类似的编译错误。试试吧。)

Why is this an error?为什么这是一个错误? After all, by your reasoning, the return statement should be unreachable.毕竟,根据您的推理, return语句应该是无法访问的。

Here's the problem.这就是问题所在。 That is NOT what the JLS says.这不是 JLS 所说的。 In fact, JLS 14.21 says the following, among other things.事实上, JLS 14.21包括以下内容。 (These statements are excerpts, and I have added the numbers for clarity. "iff" is an abbreviation that the JLS uses for "if and only if".) (这些陈述是摘录,为了清楚起见,我添加了数字。“iff”是 JLS 用于“当且仅当”的缩写。)

  1. "The block that is the body of a constructor, method, instance initializer, or static initializer is reachable." “作为构造函数、方法、实例初始值设定项或静态初始值设定项的主体的块是可访问的。”

  2. "The first statement in a non-empty block that is not a switch block is reachable iff the block is reachable." “非空块中不是 switch 块的第一个语句是可到达的,如果该块是可到达的。”

  3. "A local variable declaration statement can complete normally iff it is reachable." “局部变量声明语句可以正常完成,如果它是可达的。”

  4. "Every other statement S in a non-empty block that is not a switch block is reachable iff the statement preceding S can complete normally." “如果 S 之前的语句可以正常完成,则非 switch 块的非空块中的所有其他语句 S 都是可访问的。”

  5. "An expression statement can complete normally iff it is reachable." “表达式语句可以正常完成,如果它是可达的。”

Consider the body of method1 .考虑method1的主体。

  • By #1 - the block is reachable通过 #1 - 该块是可访问的
  • By #2 - the declaration of result is reachable.通过#2 - result的声明是可达的。
  • By #3 - the declaration can complete normally通过#3 - 声明可以正常完成
  • By #4 - the call to method2() is reachable通过#4 - 对method2()的调用是可达的
  • By #5 - the call can return normally通过#5 - 呼叫可以正常返回
  • By #4 - the return statement is reachable.通过#4 - return语句是可达的。

But it is also clear that if we reached the return statement, then result will not have been definitely initialized.但同样清楚的是,如果我们到达了return语句,那么result将不会被确定地初始化。 (This is obviously true. And JLS 16 bears this out.) (这显然是真的 。JLS 16证实了这一点。)


OK so why did they specify Java this way?好吧,为什么他们以这种方式指定 Java?

In the general case, method1 and method2 can be in separate compilation units;一般情况下, method1method2可以在不同的编译单元中; eg cases A and B .例如情况AB That means that the methods can be compiled at different times, and only brought together at runtime.这意味着这些方法可以在不同的时间编译,并且只能在运行时组合在一起。 Now, if the compiler needs to analyze the body of B.method2 to determine if the return in A.method1 is reachable, then consider what happens if:现在,如果编译器需要分析B.method2的主体以确定B.method2中的return A.method1是否可达,那么考虑以下情况会发生什么:

  • the code for B.method2 is modified and B recompiled after compiling A , or用于码B.method2被修改和B编译后重新编译A ,或
  • a subclass C of B is loaded in which C.method2 returns normally.加载B的子类C ,其中C.method2正常返回。

In short, if we need to take account of the flow within of method2 when analyzing reachability in method , we cannot come to a come to a answer at compile time.总之,如果我们在分析method可达性时需要考虑method2内部的流程,我们无法在编译时得出答案。


Conclusions:结论:

  1. The JLS clearly says / means that the (my) example program is erroneous. JLS 明确表示 / 意味着(我的)示例程序是错误的。
  2. It is not a specification mistake.这不是规格错误。
  3. If Android Studio (or javac ) didn't call the example erroneous, then it wouldn't be a valid implementation of Java.如果 Android Studio(或javac没有错误地调用示例,那么它就不是Java 的有效实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 volley 方法返回 JSONObject? (安卓工作室) - How to return a JSONObject with a method using volley? (android studio) 如何告诉Android Studio变量可能为null? - How to tell Android Studio that a variable may become null? 方法不会覆盖或实现超类型 Android Studio 中的方法 - method does not override or implement a method from a supertype Android Studio Java / Android Studio-协方差返回类型-“子类”中的方法与“基类”中的方法冲突:尝试使用不兼容的返回类型 - Java/Android Studio - Covariant Return Type - Method in “subclass” clashes with method in “baseclass”: attempting to use incompatible return type 如何在android studio中添加一个方法? - how do I add a method in android studio? 如何解决android studio中的push()方法错误 - how to resolve push() method error in android studio 如何在Android Studio中使用View参数调用方法 - How to call method with View Parameter in Android Studio 如何在 android studio 中退出 onBackPressed 方法? - How to exit onBackPressed method in android studio? 如何在onDestroy()android Studio中停止blink方法? - How to stop blink method in onDestroy() android Studio? 如何在 Android Studio 上使用 View Parameter 调用方法 - How to call method with View Parameter on Android Studio
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM