In Java 8 it looks like the lambdas of a class are kept in an array. For example, lets say we have this class:
public class LambdaFactory {
public Supplier<Integer> getOne(){
return () -> 42;
}
public Supplier<Integer> getTwo(){
return () -> 128;
}
public Supplier<Integer> getThree(){
return () -> 3;
}
}
and then I print it out like so:
System.out.println(factory.getOne());
System.out.println(factory.getOne());
System.out.println(factory.getTwo());
System.out.println(factory.getThree());
the output will be something like
examples.LambdaFactory$$Lambda$1#4e515669
examples.LambdaFactory$$Lambda$1#4e515669
examples.LambdaFactory$$Lambda$2#1b9e1916
examples.LambdaFactory$$Lambda$3#ba8a1dc
So we can see two thing here. The same lambda called twice gives us the same lambda object (this is not the same as with anon inner classes where we could get a new one every time). We also see that they look like they are being kept in some kind of "Lambda" structure that is part of the class
My question is, can I get ahold of the lambdas in a class? I don't have any reason to do so, I just like dissecting things
The lambdas are created by the JRE and the way they are created is controlled by the JRE and might vary between different JRE vendors and might change in future versions.
If you want to have fun you can create a lambda at runtime which has no corresponding information within the class file:
import java.lang.invoke.*;
public class ManualLambda {
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup me=MethodHandles.lookup();
MethodType t=MethodType.methodType(void.class);
MethodType rt=MethodType.methodType(Runnable.class);
CallSite site = LambdaMetafactory.metafactory(
me, "run", rt, t, me.findStatic(ManualLambda.class, "sayHello", t), t);
MethodHandle factory=site.getTarget();
Runnable r=(Runnable)factory.invoke();
System.out.println("created lambda: "+r);
r.run();
}
private static void sayHello() {
System.out.println("hello world");
}
}
The code above retraces what happens when a lambda is created. But for compile-time (“real”) lambda expressions the entire thing is triggered by a single invokedynamic byte code instruction. The LambdaMetafactory.metafactory(…) method is the bootstrap method which is called when the invokedynamic instruction is executed the first time. The returned CallSite object is permanently associated with the invokedynamic instruction. If the CallSite is a ConstantCallSite and its MethodHandle returns the same lambda object on every execution, the invokedynamic instruction will “produce” the same lambda instance forever.
The Java Language Specification states
At run time, evaluation of a lambda expression is similar to
evaluation of a class instance creation expression, insofar as normal
completion produces a reference to an object. [...]
Either a new instance of a class with the properties below is
allocated and initialized, or an existing instance of a class with the
properties below is referenced.
[...]
These rules are meant to offer flexibility to implementations of the
Java programming language, in that:
A new object need not be allocated on every evaluation.
[...]
As such, it is up to a compiler or run time environment to decide what should be returned when a lambda expression is evaluated.
My question is, can I get ahold of the lambdas in a class? I don't
have any reason to do so, I just like dissecting things
You can think of a lambda expression as any other class constant, a String, an integer literal, etc. These are constants that appear in the constant pool of a .class file. These are references to objects that are created and exist at run time. There is no way to refer to the actual objects from a class' constant pool.
In the case of a lambda, it wouldn't be helpful anyway because it might not actually be the same object.
Related
As far as I know, when you define a method in a function, an object is instantiated:
myList.stream().map(x->x.getName().replaceAll('a','b')).toList();
Or the equivalent
Function<MyObject,String> myFunc = x -> {return x.getName().replaceAll('a','b');}
myList.stream().map(myFunc).toList();
x->x.getName().replaceAll('a','b') is created as a functional interface object (and requires memory allocation, a new somewhere/somehow, right?).
However, if I pass an already existing method as a parameter, is anything created?
class A{
public list<String> transform(List<String> input){
return input.stream().filter(this::myFilter).filter(A::staticFilter).toList();
}
public boolean myFilter(String s){ // Whatever }
public static boolean staticFilter(String s) { // whatever }
}
What happens here:
Is myFilter "wrapped" in a functional interface? (is it the same for a static method reference?)
Is there something specific that happens at bytecode level which is not "clear" on language level (like method pointer or something?).
From JavaDoc Api
Note that instances of functional interfaces can be created with
lambda expressions, method references, or constructor references.
As to if the lambda expression will create an instance in heap or not, you can follow this thread where the top comment from #Brian Goetz might be helpful.
About lambda expressions:
Also as indicated here in Java Specifications for Run-Time Evaluation of Lambda Expressions
These rules are meant to offer flexibility to implementations of the
Java programming language, in that:
A new object need not be allocated on every evaluation.
Objects produced by different lambda expressions need not belong to
different classes (if the bodies are identical, for example).
Every object produced by evaluation need not belong to the same class
(captured local variables might be inlined, for example).
If an "existing instance" is available, it need not have been created
at a previous lambda evaluation (it might have been allocated during
the enclosing class's initialization, for example).
So to your question:
x->x.getName().replaceAll('a','b') is created as a functional
interface object (and requires memory allocation, a new
somewhere/somehow, right?).
The answer is some times yes, some times no. Not always the same case.
About method reference expressions:
Evaluation of a method reference expression produces an instance of a
functional interface type (§9.8). Method reference evaluation does not
cause the execution of the corresponding method; instead, this may
occur at a later time when an appropriate method of the functional
interface is invoked.
Based on what is written here for Run-Time Evaluation of Method References
The timing of method reference expression evaluation is more complex
than that of lambda expressions (§15.27.4). When a method reference
expression has an expression (rather than a type) preceding the ::
separator, that subexpression is evaluated immediately. The result of
evaluation is stored until the method of the corresponding functional
interface type is invoked; at that point, the result is used as the
target reference for the invocation. This means the expression
preceding the :: separator is evaluated only when the program
encounters the method reference expression, and is not re-evaluated on
subsequent invocations on the functional interface type.
I would assume that a functional interface type is created but not each time with each invocation. It should as well be cached and optimized for the less amount of evaluations.
Well, the compiler has a lot of leeway in how it actually implements the code you write, but generally .map() takes a Function Object so whatever expression you put in the parentheses will produce an object.
That does not mean, however, that a new Object is created every time. In your lambda example, the lambda function doesn't reference anything defined in an enclosing method scope, so a single Function object can be created and reused for all calls.
Similarly, the A::staticFilter reference only needs to produce one Function.
The object created by this::myFilter, however, needs to have a reference to this (unless the compiler can determine that it doesn't!), and so you will certainly get a new Function created inside each call to transform.
This question has been previously asked over here
My question regarding why which was answered over here
But I have some doubts about the answer.
The answer provided mentions-
Although other answers prove the requirement, they don't explain why the requirement exists.
The JLS mentions why in §15.27.2:
The restriction to effectively final variables prohibits access to dynamically-changing local variables, whose capture would likely introduce concurrency problems.
To lower the risk of bugs, they decided to ensure captured variables are never mutated.
I am confused by the statement that it would lead to concurrency problems.
I read the article about concurrency problems on Baeldung but still, I am a bit confused about how it will cause concurrency problems, can anybody help me out with an example.
Thanks in advance.
I'd like to preface this answer by saying what I show below is not actually how lambdas are implemented. The actual implementation involves java.lang.invoke.LambdaMetafactory if I'm not mistaken. My answer makes use of some inaccuracies to better demonstrate the point.
Let's say you have the following:
public static void main(String[] args) {
String foo = "Hello, World!";
Runnable r = () -> System.out.println(foo);
r.run();
}
Remember that a lambda expression is shorthand for declaring an implementation of a functional interface. The lambda body is the implementation of the single abstract method of said functional interface. At run-time an actual object is created. So the above results in an object whose class implements Runnable.
Now, the above lambda body references a local variable from the enclosing method. The instance created as a result of the lambda expression "captures" the value of that local variable. It's almost (but not really) like you have the following:
public static void main(String[] args) {
String foo = "Hello, World!";
final class GeneratedClass implements Runnable {
private final String generatedField;
private GeneratedClass(String generatedParam) {
generatedField = generatedParam;
}
#Override
public void run() {
System.out.println(generatedField);
}
}
Runnable r = new GeneratedClass(foo);
r.run();
}
And now it should be easier to see the problems with supporting concurrency here:
Local variables are not considered "shared variables". This is stated in §17.4.1 of the Java Language Specification:
Memory that can be shared between threads is called shared memory or heap memory.
All instance fields, static fields, and array elements are stored in heap memory. In this chapter, we use the term variable to refer to both fields and array elements.
Local variables (§14.4), formal method parameters (§8.4.1), and exception handler parameters (§14.20) are never shared between threads and are unaffected by the memory model.
In other words, local variables are not covered by the concurrency rules of Java and cannot be shared between threads.
At a source code level you only have access to the local variable. You don't see the generated field.
I suppose Java could be designed so that modifying the local variable inside the lambda body only writes to the generated field, and modifying the local variable outside the lambda body only writes to the local variable. But as you can probably imagine that'd be confusing and counterintuitive. You'd have two variables that appear to be one variable based on the source code. And what's worse those two variables can diverge in value.
The other option is to have no generated field. But consider the following:
public static void main(String[] args) {
String foo = "Hello, World!";
Runnable r = () -> {
foo = "Goodbye, World!"; // won't compile
System.out.println(foo);
}
new Thread(r).start();
System.out.println(foo);
}
What is supposed to happen here? If there is no generated field then the local variable is being modified by a second thread. But local variables cannot be shared between threads. Thus this approach is not possible, at least not without a likely non-trivial change to Java and the JVM.
So, as I understand it, the designers put in the rule that the local variable must be final or effectively final in this context in order to avoid concurrency problems and confusing developers with esoteric problems.
When an instance of a lambda expression is created, any variables in the enclosing scope that it refers are copied into it. Now, suppose if that were allowed to modify, and now you are working with a stale value which is there in that copy. On the other hand, suppose the copy is modified inside the lambda, and still the value in the enclosing scope is not updated, leaving an inconsistency. Thus, to prevent such occurrences, the language designers have imposed this restriction. It would probably have made their life easier too. A related answer for an anonymous inner class can be found here.
Another point is that you will be able to pass the lambda expression around and if it is escaped and a different thread executes it, while current thread is updating the same local variable, then there will be some concurrency issues too.
It is for the same reason the anonymous classes require the variables used in their coming out from the scope of themselves must be read-only -> final.
final int finalInt = 0;
int effectivelyFinalInt = 0;
int brokenInt = 0;
brokenInt = 0;
Supplier<Integer> supplier = new Supplier<Integer>() {
#Override
public Integer get() {
return finalInt; // compiles
return effectivelyFinalInt; // compiles
return brokenInt; // doesn't compile
}
};
Lambda expressions are only shortcuts for instances implementing the interface with only one abstract method (#FunctionalInterface).
Supplier<Integer> supplier = () -> brokenInt; // compiles
Supplier<Integer> supplier = () -> brokenInt; // compiles
Supplier<Integer> supplier = () -> brokenInt; // doesn't compile
I struggle to read the Java Language specification to provide support to my statements below, however, they are logical:
Note that evaluation of a lambda expression produces an instance of a functional interface.
Note that instantiating an interface requires implementing all its abstract methods. Doing as an expression produces an anonymous class.
Note that an anonymous class is always an inner class.
Each inner class can access only final or effectively-final variables outside of its scope: Accessing Members of an Enclosing Class
In addition, a local class has access to local variables. However, a local class can only access local variables that are declared final. When a local class accesses a local variable or parameter of the enclosing block, it captures that variable or parameter.
I know about lambda method references.
However, I am wondering whether the reverse might be possible, because I have a method that just proxies its arguments to a lambda:
Function<Arg, Result> lambda = (a) -> new Result(a);
public Result myMethod(Arg arg) {
return lambda.apply(a);
}
Haven't found anything on Google, so I guess it's not possible. Which makes sense, because after all, as I understand it, a lambda is just shorthand for a whole interface. A method and an interface are different. But you can make a lambda from a method, so maybe you can make a method from a lambda?
You can't make a method from a lambda because, as you say, a lambda is not a method and more importantly you cannot dynamically change a class by adding methods to it at runtime. That's a basic design invariant of Java classes. It is possible to dynamically respond to a predefined method of an interface with your own implementation, although it's fairly clunky. Take a look at http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html
The variable lambda has the type Function which doesn’t say anything about how the instance has been created. It might be a lambda expression, but it doesn’t have to. That said, if you want to delegate myMethod to a method declared in Function, there is no reason to automatically choose the abstract method of that interface, so, similar to method references, you would have to specify the target method like lambda::apply to make clear you want that method and not one of the other methods of the interface Function.
But unlike method references, which use a target type, you can’t derive a method declaration from the surrounding context, so you can’t spare the method declaration. So such a hypothetical feature would still require the method declaration, the reference to the lambda field and the target method name (apply), so there is not much left that you can save that would justify a new language feature.
And there is no need for such a functionality anyway. If you have code to be expressed as both, a function and a method, express it as method:
Instead of
Function<Arg, Result> lambda = (a) -> new Result(a);
public Result myMethod(Arg arg) {
return lambda.apply(a);
}
write
Function<Arg, Result> lambda = this::myMethod;
public Result myMethod(Arg arg) {
return new Result(arg);
}
But even a code replication might be acceptable, as in
Function<Arg, Result> lambda = (a) -> new Result(a);
public Result myMethod(Arg arg) {
return new Result(arg);
}
considering that lambda expressions should host rather small, often trivial, code only.
This question already has answers here:
Is there a way to compare lambdas?
(3 answers)
Closed 8 years ago.
The following test fails
#Test
public void test() {
Function<String, Integer> foo = Integer::parseInt;
Function<String, Integer> bar = Integer::parseInt;
assertThat(foo, equalTo(bar));
}
is there any way to make it pass?
edit: I'll try to make it more clear what I'm trying to do.
Lets say I have these classes:
class A {
public int foo(Function<String, Integer> foo) {...}
}
class B {
private final A a; // c'tor injected
public int bar() {
return a.foo(Integer::parseInt);
}
}
now lets say i want to write unit test for B:
#Test
public void test() {
A a = mock(A.class);
B b = new B(a);
b.bar();
verify(a).foo(Integer::parseInt);
}
the problem is that the test fails, because the method references are not equal.
Lambdas are not cached and this seems to be deliberate. There is no way to compare two lambdas to see if they would do the same thing.
You need to do something like
static final Function<String, Integer> parseInt = Integer::parseInt;
#Test
public void test() {
Function<String, Integer> foo = parseInt;
Function<String, Integer> bar = parseInt;
assertThat(foo, equalTo(bar));
}
Answer from Brian Goetz; Is there a way to compare lambdas?
I don't have the API at hand, but Function is an interface. Integer::parseInt seems not to cache, so it will return two different instances, which will be compared by reference => false.
You can make it pass by writing a Comparator, which does what you want.
Have look at the Java Language Specification:
15.27.4. Run-time Evaluation of Lambda Expressions
At run time, evaluation of a lambda expression is similar to evaluation of a class instance creation expression, insofar as normal completion produces a reference to an object. Evaluation of a lambda expression is distinct from execution of the lambda body.
Either a new instance of a class with the properties below is allocated and initialized, or an existing instance of a class with the properties below is referenced.
…
These rules are meant to offer flexibility to implementations of the Java programming language, in that:
A new object need not be allocated on every evaluation.
Objects produced by different lambda expressions need not belong to different classes (if the bodies are identical, for example).
Every object produced by evaluation need not belong to the same class (captured local variables might be inlined, for example).
If an "existing instance" is available, it need not have been created at a previous lambda evaluation (it might have been allocated during the enclosing class's initialization, for example).
In principle, this implies that even a single occurrence of Integer::parseInt in your source code may lead to different object instances (even of different classes) when being evaluated multiple times, not to speak of multiple occurrences of it. The exact decision is left to the actual JRE implementation. See this answer discussing the current behavior of Oracle’s implementation.
It's OK that the test doesn't pass. Lambdas are not objects, they are not subject to properties such as object identity. Instead they are adhoc implementations of functional interfaces.
I believe you shouldn't be expecting your code to rely on the behavior you have described.
Reading up on the Java-8 spec, I keep seeing references to 'SAM types'. I haven't been able to find a clear explanation of what this is.
What is a SAM type and what is an example scenario of when one might be used?
To summarize the link Jon posted1 in case it ever goes down, "SAM" stands for "single abstract method", and "SAM-type" refers to interfaces like Runnable, Callable, etc. Lambda expressions, a new feature in Java 8, are considered a SAM type and can be freely converted to them.
For example, with an interface like this:
public interface Callable<T> {
public T call();
}
You can declare a Callable using lambda expressions like this:
Callable<String> strCallable = () -> "Hello world!";
System.out.println(strCallable.call()); // prints "Hello world!"
Lambda expressions in this context are mostly just syntactic sugar. They look better in code than anonymous classes and are less restrictive on method naming. Take this example from the link:
class Person {
private final String name;
private final int age;
public static int compareByAge(Person a, Person b) { ... }
public static int compareByName(Person a, Person b) { ... }
}
Person[] people = ...
Arrays.sort(people, Person::compareByAge);
This creates a Comparator using a specific method that doesn't share the same name as Comparator.compare, that way you don't have to follow the interface naming of methods and you can have multiple comparison overrides in a class, then create the comparators on the fly via the lambda expressions.
Going Deeper...
On a deeper level, Java implements these using the invokedynamic bytecode instruction added in Java 7. I said earlier that declaring a Lambda creates an instance of Callable or Comparable similar to an anonymous class, but that's not strictly true. Instead, the first time the invokedynamic is called, it creates a Lambda function handler using the LambdaMetafactory.metafactory method, then uses this cached instance in future invocations of the Lambda. More info can be found in this answer.
This approach is complex and even includes code that can read primitive values and references directly from stack memory to pass into your Lambda code (e.g. to get around needing to allocate an Object[] array to invoke your Lambda), but it allows future iterations of the Lambda implementation to replace old implementations without having to worry about bytecode compatibility. If the engineers at Oracle change the underlying Lambda implementation in a newer version of the JVM, Lambdas compiled on an older JVM will automatically use the newer implementation without any changes on the developer's part.
1 The syntax on the link is out of date. Take a look at the Lambda Expressions Java Trail to see the current syntax.