'Using return inside a lambda?

In the code below, I want to show my empty views if trips is empty and then return and avoid running the below code, but the compiler says "return is not allowed here".

mainRepo.fetchUpcomingTrips { trips ->
    if (trips.isEmpty()) {
        showEmptyViews()
        return
    }

    // run some code if it's not empty
}

Is there a way to return like that?

I know I can just put it in an if else block but I hate writing if else's, it's less understandable/readable in my opinion when there's a few more conditions.



Solution 1:[1]

You can also replace { trips -> with fun(trips) { to form an anonymous function which can use return normally.

Solution 2:[2]

Plain return suggests that you return from the function. Since you can't return from the function inside a lambda, the compiler will complain. Instead, you want to return from the lambda, and you have to use a label:

mainRepo.fetchUpcomingTrips { trips ->
    if (trips.isEmpty()) {
        showEmptyViews()
        return@fetchUpcomingTrips
    }

    //run some code if it's not empty
}

Solution 3:[3]

An alternative to the return might be

mainRepo.fetchUpcomingTrips { trips ->
            if (trips.isEmpty())
                showEmptyViews()
            else {
                //run some code if it's not empty
            }
        }

Solution 4:[4]

The returns allow us to return from an outer function. The most important use case is returning from a lambda expression

A return statement in an anonymous function will return from the anonymous function itself.

fun foo() {
    ints.forEach(fun(value: Int) {
        if (value == 0) return  // local return to the caller of the anonymous fun, i.e. the forEach loop
        print(value)
    })
}

When returning a value, the parser gives preference to the qualified return, i.e.

return@a 1

means "return 1 at label @a" and not "return a labeled expression (@a 1)".

Return By default returns from the nearest enclosing function or anonymous function.

Break Terminates the nearest enclosing loop.

Continue Proceeds to the next step of the nearest enclosing loop.

More details refer Returns and Jumps,Break and Continue Labels

Solution 5:[5]

You can Return to Labels:

fun foo() {
    println("begin foo")
    listOf(1, 2, 3, 4, 5).forEach lit@{
        // local return, meaning this function execution will end
        // the forEach will continue to the next element in the loop
        if (it == 3) return@lit
        
        println("- $it")
    }
    println("done with explicit label")
}

Playground demo here.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Solomon Ucko
Solution 2 Ilya
Solution 3 elect
Solution 4 Ilya
Solution 5