In Kotlin, a lambda expression or anonymous function (as well as a local function and an object expression) can access its closure, which includes the variables declared in the outer scope. The variables captured in the closure can be modified within the lambda.

Here is an example from Kotlin’s website:

var sum = 0
ints.filter { it > 0 }.forEach {
    sum += it
}
print(sum)

Java 8 introduced lambdas, which can access external variables but cannot modify them. This limitation restricts the ability to perform functional programming in Java 8.

This example will result in a compilation error:

List<String> strings = Arrays.asList("sup1", "sup2", "sup3");
List<String> transformers = Arrays.asList("trans1", "trans2", "trans3");

@Test
public void demo2() {
    strings.stream().map(s -> transformers.stream().forEach(t -> {  // There will be error here.
        s = (t + ", " + s);
    })).forEach(System.out::println);
}
error: incompatible types: inference variable R has incompatible bounds
        strings.stream().map(s -> transformers.stream().forEach(t -> {
                            ^
    lower bounds: Object
    lower bounds: void
  where R,T are type-variables:
    R extends Object declared in method <R>map(Function<? super T,? extends R>)
    T extends Object declared in interface Stream

but not in Kotlin.

var strings: List<String> = mutableListOf("sup1", "sup2", "sup3")
var transformers: List<String> = mutableListOf("trans1", "trans2", "trans3")

@Test
fun demo2() {
    strings.stream().map<Any> { s: String ->
        var s = s
        transformers.stream().forEach { t: String -> s = "$t, $s" }
    }.forEach { o: Any? -> println(o) }
}

Extended link: