Question related to frames of function and effective finality of variables.
int lenMin = list.get(0).length();
for (String s : list)
if (s.length() < lenMin)
lenMin = s.length();
list
.stream()
.filter(s -> lenMin == s.length())
.forEach(System.out::println);
st:1. here we create a variable.
st: 3-5 here we do something with it (change it).
st:9 the lenMin variable is underlined in red.
Effectivity finality we cannot change, but can we use it? I know that the lambda has a new frame, but if we do this:
int len = lenMin;
list
.stream()
.filter(s -> len == s.length())
.forEach(System.out::println);
then there will be no error.
Please explain why this is happening?
Functions that can close over variables need a way to capture those variables.
If a variable can't change, then you can easily capture variables by copying their values.
Java does exactly that. Java lambdas, and inner classes simply correspond to classes that have an extra field for each captured variable.
The JVM only understands flat classes; nested and inner classes are compiler fictions.
Runnable f() {
int answer = 42;
class C extends Runnable {
public void run() { System.out.println(answer); }
}
return new C();
}
compiles to something equivalent to
class C {
private int answer; // Capturing field
C(int answer) { this.answer = answer }
void run() { System.out.println(this.answer); }
}
Runnable f() {
int answer = 42;
return new C(answer);
}
This change is called closure conversion.
As long as answer is only assigned once, javac can do simple closure conversion: copying answer into any classes and lambdas that need it.
But simple copying doesn't work if a local variable might change after being captured.
int answer = 42;
Runnable c = new C();
answer += 1;
c(); // Should this print 42 or 43?
Programmers familiar with languages that allow for reassignment of closed-over variables would get confused if the above didn't behave like the JavaScript below.
let answer = 42;
let c = () => console.log(answer);
answer += 1;
c(); // Logs 43
Java could allow for mutable closed-over variables by doing more complicated closure conversion. For example, instead of copying answer, storing answer in a shared object and rewriting reads&writes to be reads/writes of a property or element of that shared object.
For example,
int[] answerBox = new int[1];
answerBox[0] = 42; // assignment
...
answerBox[0] = 43; // re-assignment
...
System.out.println(answerBox[0]);
...
Java's designers decided not to do that though; capturing by-reference the way JavaScript does would introduce a host of subtle complications. JavaScript is single threaded, but the JVM is not, so imagine when a closed over long variable is suddenly assigned in more than one thread.
This is not hard to work around though as long as you don't need to mutate captured state after creating the capturing value.
Runnable f() {
int x = 1;
x += 1;
return () -> System.out.println(x); // ERROR
}
The above fails, but the below works; we simply store the state of the non-effectively-final x in an effectively final finalX that the lambda can capture.
Runnable f() {
int x = 1;
x += 1;
int finalX = x;
return () -> System.out.println(finalX); // OK
}
So the question is: why one has to introduce a new copy, to have a variable, that is effectively final (= could be made final). Here len.
int len = lenMin;
list
.stream()
.filter(s -> len == s.length())
.forEach(System.out::println);
The reason that the lambda (inside filter) is an anonymous implemented interface instance, that uses len as follows: as it is a local variable, it copies it into a local interface variable with the same name len.
But now one has two variables (though same names). As the lambda theoretically could run in another thread, one has two threads that can change same named variables differently. The language designers did not want to allow two lens with different values, and simply required that the variable is not changed, effectively final.
Here it would not be dangerously misleading, but assume you later assign to len at the end or inside a lambda, and perhaps use .parallelStream(). Then suddenly a compile error must be given at an unchanged piece of code.
That is an additionally sufficient reason to keep the rule simple: a local variable used inside a lambda must be effectively final.
Related
Was going through a closure example for the first time , but I'm having a hard time wrapping my head around the control flow.
public class TestLambdaClosure {
public static void main(String[] args) {
int a= 10;
int b=20;
//doProcess(a, i-> System.out.println(i+b));
doProcess(a, new Process() {
#Override
public void process(int i) {
System.out.println(i+b);
}
});
}
public static void doProcess(int i, Process p) {
p.process(i);
}
interface Process{
void process(int i);
}
}
How does 'b' get in the scope when p.process(i) is called? Also, how does the control flow work here internally?
Closures allow you to model behavior by encapsulating both code and context into a single construct.
The key concept is that your function code (lambda) can refer to not only its own variables, but also to everything outside visible for the code, variables a and b in your case.
In Java, closures can refer only to final or effectively final variables. It means, the reference of the variable cannot change and the closure sees only the actual immutable state (the value is actually not immutable, final means the variable cannot be reassigned). In the theory, this is not necessary. For example in JavaScript, you can write such code:
function newCounter() {
let count = 0;
return function() { return ++count; };
}
const nc = newCounter();
console.log(nc()); // 1
console.log(nc()); // 2
console.log(nc()); // 3
Here, the inner function of newCounter still has access to count (its context) and can modify it (the variable is mutable).
Notice, that variable counter is not accessible to any other parts of your code outside of the closure.
Closures let you access variables in their outer scopes. Outer scope variable in this case (b) is declared as what java community now it calls effectively final, meaning that it's value isn't changed since initialization ( int b = 20 ) in order to be accessible.
Bare in mind that variables need to be declared as final or effectively final in order for this to work as closures.
Now regarding your code, this code declares doProcess(...) method that returns a method for partial performing of the doProcess(...) method.
The process(...) method accesses b in the outer scope of the doProcess(...) method, which is declared as effectively final.
This question already has answers here:
Variable used in lambda expression should be final or effectively final
(9 answers)
Closed 4 years ago.
I would like to use local variables in lambda functions but I get error:
Please see the 1. and 2. points in the code.
class Foo {
int d = 0; // 1. It compiles, but ugly, 2. doesnt compile
public void findMax(List<List<Route>> routeLists) {
int d = 0; // 2.Error : Local variable dd defined in an enclosing scope must be final or effectively final
routeLists.forEach(e-> {
e.forEach(ee -> {
d+=ee.getDistance();
});
});
... doing some other operation with d
}
}
How can I use them whitout setting them as global variables ?
forEach is the wrong tool for the job.
int d =
routeLists.stream() // Makes a Stream<List<Route>>
.flatMap(Collection::stream) // Makes a Stream<Route>
.mapToInt(Route::getDistance) // Makes an IntStream of distances
.sum();
Or just use nested for loops:
int d = 0;
for (List<Route> rs : routeLists) {
for (Route r : rs) {
d += r.getDistance();
}
}
You can't use an int as variable because it must be final to be used in a stream.
But You can create a class wrapping the int.
Then declare the variable holding this class as final.
Changing the content of the inner int variable.
public void findMax(List<List<Route>> routeLists) {
final IntWrapper dWrapper = new IntWrapper();
routeLists.forEach(e-> {
e.forEach(ee -> {
dWrapper.value += ee.getDistance();
});
});
int d = dWrapper.value;
... doing some other operation with d
}
public class IntWrapper {
public int value;
}
Having side effects is discouraged (or even forbidden?) in the functions used in a stream.
A better way would be one of
routeLists.stream()
.flatMapToInt(innerList -> innerList.stream()
.mapToInt(Route::getDistance))
.sum()
or
routeLists.stream()
.mapToInt(innerList -> innerList.stream()
.mapToInt(Route::getDistance).sum())
.sum()
The first will, for each sublist, create a stream of distances. All these streams will become flattened and summed at once.
The second will create the sum of each sublist and then add all those sums together again.
They should be equivalent, but I am not sure if the one or other is better in terms of performance (i. e., if flattening the streams is more expensive than summing).
A third alternative of flattening the lists and then getting and summing the distances is covered by Andy Turner's answer.
In Python, I can define two variables with an array in one line.
>>>[a,b] = [1,2]
>>>a
1
>>>b
2
How do I do the same thing in Java?
I have a couple of variables in class PCT which type is final. Is there a way to define them in one line in a Python like fashion? The following format clearly does not work in Java. I could define them separately, but it will call the parseFile method twice which I want to avoid.
public class PCT {
final int start;
final int stop;
public PCT (File file) {
//......
//......
// the following statement does not compile
[start, stop] = parseFile(file);
}
public int[] parseFile(File f) {
int[] aa = new int[2];
// ....
// ....
return aa;
}
}
You can define multiple variables like this :
double a,b,c;
Each variable in one line can also be assigned to specific value too:
double a=3, b=5.2, c=3.5/3.5;
One more aspect is, while you are preparing common type variable in same line then from right assigned variables you can assign variable on left, for instance :
int a = 4, b = a+1, c=b*b;
Noticed, you can also practice arithmetic operations on variable by remaining in the same line.
This is not possible, but you also don't need to call parseFile twice.
Write your code like this:
int [] temp = parseFile(file);
start = temp[0];
stop = temp[1];
Python (I believe) supports multiple return values. Java obeys C conventions, and so doesn't permit it. Since that isn't part of the language, the syntax for it isn't either, meaning slightly gross hacks like the temp array are needed if you're doing multiple returns.
When declaring several variables of the same type, you can do the following:
int a = 1, b = 2, c = 3; //etc.
If you literaly mean line; as long as you place a semicolon in between two statements, they are executed as if there is a new line in between so you can call:
a = 1; b = 2;
You can even compress an entire file into a oneliner, by removing comment (that scope to the end of the line). Spacing (space, tab, new line,...) is in general removed from the Java files (in memory) as first step in the Java compiler.
But you are probably more interested in a singe statement. Sytax like [start, stop] = parseFile(file); is not supported (at least not for now). You can make a onliner:
int[] data = parseFile(file); start = data[0]; stop = data[1];
Maybe this is what you're looking for:
int array[] = {1,2};
Java array assignment (multiple values)
If you're looking to explicitly assign to each element, I don't think you can do that within one assignment, as a similar concept with the 2-d example below. Which seems like what you want as Jeremy's answers specifies.
Explicitly assigning values to a 2D Array?
Maybe
public class PCT
{
final Point pos; // two ints!
public PCT (File file)
{
pos = parseFile(file);
}
public int[] parseFile(File f)
{
Point aa = new Point();
// ....
// ....
return aa;
}
}
I have problem understanding the order in which initialization happens. this is the order I assumed:
*Once per
1. Static variable declaration
2. Static block
*Once per object
3. variable declaration
4. initialization block
5. constructor
but according to this code I am obviously wrong:
class SomethingWrongWithMe
{
{
b=0; //no. no error here.
int a = b; //Error: Cannot reference a field before it is defined.
}
int b = 0;
}
And the error would disappear if I do this:
class SomethingWrongWithMe
{
int b = 0;
{
b=0;
int a = b; //The error is gone.
}
}
I can't figure out why isn't there an error on
b=0;
The Java Language Specification (section 8.3.2.3) says you can use a variable on the left hand side of an expression, i.e. assign to it, before it is declared, but you cannot use it on the right hand side.
All variables are initialized to their default values, then explicit initializers and anonymous blocks are run in the order they are found in the source file. Finally the constructor is called.
Statics are only run once on the first use of a class.
The compile error appears to be a rule of Java rather than something that necessarily makes sense in every case.
Variable definitions are not done "before" blocks. They are both done at the same time, in the order that they are defined
class SomethingWrongWithMe {
{
b = debug("block 1");
}
int b = debug("define");
{
b = debug("block 2");
}
private int debug(String str) {
System.out.println(str);
return 0;
}
}
Output
block 1
define
block 2
First of all, your assumptions are more or less correct, except for the fact that declarations (with initialization, such as int b = 0) and instance initializer blocks are executed in the order they are written.
int b = 0; // executed first
{
b = 1; // executed second
}
int a = b; // executed third
Also note that the declaration i.e. int b is not executed. The declaration just declares the existence of the variable.
As for the error you got (or, rather the error you didn't get) I agree that it looks strange. I assume that the compiler deals with referencing a variable in an expression and assigning a value to it in different ways. When writing to a variable in an instance initializer, it just checks that the variable is there, while when reading from it, it requires it to be declared above the instance initializer block. I'll see if I can find a reference for that in the JLS.
This question already has answers here:
How to write a basic swap function in Java [duplicate]
(19 answers)
Java method to swap primitives
(8 answers)
Closed 6 years ago.
Here is the question: write a method that swaps two variables. These two variables should be primitives. It doesn't need to be generic e.g. two int variables. Is there a way?!
While it is not possible to write a function that simply swaps two variables, it is possible to write a helper function that allows you to:
Swap two variables using only one statement
Without temporary variables in the caller's code
Without 'boxing' primitives
With a few overloads (one of them using generics), it works for any type
That's how you could do it:
int returnFirst(int x, int y) {
return x;
}
<T> T returnFirst(T x, T y) {
return x;
}
// other overloads as needed
int a = 8, b = 3;
a = returnFirst(b, b = a); // try reading this as a = b; b = a;
System.out.println("a: " + a + ", b: " + b); // prints a: 3, b: 8
This works because the Java language guarantees (Java Language Specification, Java SE 7 Edition, section 15.12.4.2) that all arguments are evaluated from left to right (unlike some other languages, where the order of evaluation is undefined), so the execution order is:
The original value of b is evaluated in order to be passed as the first argument to the function
The expression b = a is evaluated, and the result (the new value of b) is passed as the second argument to the function
The function executes, returning the original value of b and ignoring its new value
You assign the result to a
If returnFirst is too long, you can choose a shorter name to make code more compact (e.g. a = sw(b, b = a)).
Suppose you need to swap many variables of different types one after the other. By using returnFirst there's no need for intAux, objAux, etc. There's less risk of mistakenly using the wrong variable somewhere, because there are no extra variables (in the caller, at least).
Without using an array or objects, no, it is not possible to do it within a method.
Check out this JavaWorld article that explains it in detail:
http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html
A swap of two primitives will never work because primitives are passed by value in Java. You can't even write a method to swap two objects for that matter.
Like #Thomas said, the only thing you could do is have your primitives contained within other objects/arrays and modify those.
One-liner for any primitive numbers:
a += (b - (b = a));
You can make a generic version of #marcus's swap method that swaps any number of objects of the same type:
<T> T swap(T... args) { // usage: z = swap(a, a=b, b=c, ... y=z);
return args[0];
}
b = swap(a, a=b);
z = swap(x, x=y, y=z);
In java5, the closest I can think of, which may help you, is :
The AtomicInteger class (and others) have getAndSet() atomic methods ..
To write a swap method that swaps primitives you'd have to have the concept of "out" variables, i.e. variables whose values are passed up to the calling context. C# has those but you must still specify that they're out variables.
This function will swap two ints
Integer[] swap(int a, int b){
return new Integer[]{b,a};
}
Here's a method that swaps two primitive variables
private void swap(){
int a = 1;
int b = 2;
int temp = a;
a = b;
b = temp;
}
It might not be of much use though ;)
Ok seriously, it could be done if the variables are class level:
public class MyClass{
// excuse horrible coding practice of public mutable fields
public int a = 1;
public int b = 2;
public void swap(){
int temp = a;
a = b;
b = temp;
}
}
Again though, I fail to see what the use of this could be
I have read the above answers seeking an explanation as to why it is said that a swapping program cannot be written in java in the way it is written in c++.
I did the following way
program screenshot
As Thomas Owens said. You could probably do it in C by passing variables by &reference, but afaik not in Java without using objects.
Yes it is possible to swap two variable using a method.
But you should declare that method with empty parentheses and then call it by
reference(empty parentheses) .
Here is an example that illustrates swapping of two variable using a method.
public class Swapping
{
static String A="Apple";
static String B="Bat";
public static void swap()
{
String k;
k=A;
A=B;
B=k;
}
public static void main(String[] args)
{
System.out.println("Before swapping");
System.out.println("A= "+A);
System.out.println("B= "+B);
swap();
System.out.println("After swapping");
System.out.println("A= "+A);
System.out.println("B= "+B);
}
}
By compiling the above code the output comes as follows:
Before swapping
A= Apple
B= Bat
After swapping
A= Bat
B= Apple
//In case of call by reference original value is changed if we made changes in the called method
public class Swap
{
public static void main (String[]args)
{
int y = 5;
int x = 4;
int c;
System.out.println("y = "+y);
System.out.println("x = "+x);
c=x; //c = 4
x=y; //x = 5;
y=c;
System.out.println("\n");
System.out.println("y= "+y);
System.out.println("x= "+x);
}
}