2

Inside a Runnable block, I want to do some "guard block", like so:

var condition: String? = null
Runnable {
    if (condition == null) return
    // do something
}

but compiler says "return is not allowed here"??

Henry
  • 42,982
  • 7
  • 68
  • 84
WSBT
  • 33,033
  • 18
  • 128
  • 133
  • how about `break`? :) sorry I don't use java 11. edit: Just saw the java tag get removed, I don't know kotlin either. – SamHoque Nov 08 '18 at 06:57
  • 1
    Have you tried `return@Runnable`? – EpicPandaForce Nov 08 '18 at 06:58
  • @EpicPandaForce Thank you! `return@Runnable` works and I feel so dumb now... I searched before asking but I guess my wording wasn't good. If you post it as an answer I will accept it. – WSBT Nov 08 '18 at 06:59

2 Answers2

2

There are two ways you can make this work:

As mentioned in the comments, you can use a "qualified return" as discussed here. That's also what IntelliJ (AndroidStudio as well I guess) suggests: enter image description here

As an alternative, you can define your Runnable as an anonymous class which enables you to use ordinary return statements:

 object: Runnable {
     override fun run() {
         if (condition == null) return
         // do something
     }
 }

IntelliJ will now suggest to transform this object to a lambda which will result in the exact same thing with a qualified return:

Runnable {
    if (condition == null) return@Runnable
    // do something
}

PS: No need to feel dumb! I suppose you would have found it easily with the right wording. It's good to know what Runnable {} is here. It's basically a lambda which is based on SAM conversion (works with Java types with a single abstract method)

s1m0nw1
  • 76,759
  • 17
  • 167
  • 196
  • Thanks! It looks like IntelliJ is a lot better. Android Studio literally says "return is not allowed here" without giving suggestions. – WSBT Nov 08 '18 at 19:50
0

To expand on s1m0nw1's answer, using return@Runnable is correct.

@Runnable is, in this case, defining what you return. It also works with loops, but also methods. Here's an example with loops:

fun test(){
    one@for(i in 0..100){
        two@for(j in 0..i){
            if(j == 20){
                break;//this breaks two
            }
        }
    }
}

This example breaks the second when j == 20. If you want to break the outer loop when j is 20 (this might not be the best example, but you still get the general idea), you'd use break@one. For loops, this only works if you explicitly declare a label.

You basically have to specify what you want to break/return/continue (depending on what you use) in some cases. Returning from a regular method, or breaking a single loop doesn't need explicit labeling, but if you use lambda, or want to break outer loops, you'd target those using [return/break/continue]@LabelMethodClassOrInterfaceName.

In the example I added, if you want to return instead of break, you could use return@test. However, it's slightly pointless since return in that context implies from the method.

With this type of lambda, you're forced to use return@InterfaceName. InterfaceName is replaced with whatever interface you're using (in this case Runnable).

Or you could of course get IntelliJ to auto-complete it for you.

Zoe
  • 27,060
  • 21
  • 118
  • 148