In Java I have the following code
List<Integer> myList = new ArrayList<>();
for (int i=0;i<9;i++) {
myList.add(i);
}
Integer sum = 0;
myList.forEach(i -> {
sum = sum + i; // does not compile, sum needs to be final or effectively final
});
for(int i : myList) {
sum = sum + i; //runs without problems
}
My question is, why is it exactly that I cannot change the value of sum from within the lambda? It does the exact same thing as the for loop down below, or am I wrong? Interesting is also the fact that if I declare the Integer sum outside of the main method as static, it works as well. Can anyone explain me why?
EDIT: In another similar question Does Java 8 support closures, the answer seems to be :
it is a combination of backwards compatibility and project resourcing constraints.
However I still cannot understand why it works if I make sum an array or if I declare it outside of main. I would also like to understand what is the difference between the myList.forEach and the for loop below, why the one works and the other one doesn't.
Try with:
final Integer[] sum = new Integer[1];
sum[0] = 0;
myList.forEach(i -> {
sum[0] = sum[0] + i;
});
Since lambda is actually a syntactic sugar for initializing an anonymous class (and overriding a method).
It's the same as if you have written:
final Integer[] sum = new Integer[1];
sum[0] = 0;
myList.forEach(new Consumer() {
public void accept(Integer element) {
sum[0] = sum[0] + element;
}
});
The variable that comes from outer scope and that you use within inner scope must be final (in this example sum). That is simply because Java does not support closures. Therefore, outer variable must be marked as final. Since Integer itself is immutable (if you declare it final, you cannot change it anymore), you have to use a wrapper object or an array (as I did).
You can find more useful info here:
Why are only final variables accessible in anonymous class?
Cannot refer to a non-final variable inside an inner class defined in a different method
Not exactly the answer you are looking for, but in most scenarios you won't need to modify that inside the lambda. This is because it's not idiomatic for lambdas to be state-changing in a proper functional style.
What you can do to achieve your result is use any of the higher-level functions provided to mask the "accumulator", and then assign:
sum = myList.stream().mapToInt(x->x).sum();
A lambda is basically an anonymous class. You can only access final local variables from anonymous class.
What you need is a wrapper class that can modify its content. For a quick hack, you can use AtomicInteger in this case:
AtomicLong sum = new AtomicLong(0);
myList.forEach(i -> {
sum.addAndGet(i); // does not matter getAndAdd or addAndGet
});
sum.get(); // to get the value
Another way is, if you are using Intellij IDEA, the IDE can suggest you to transform the variable into final one element array (as in darijan's answer).
Related
I am new to java and I am working with arrays and for each loop.I am facing a problem with iterator initialization.
Code works fine when iterator variable initialization is done within for each block while code throws error when iterator initialization is done outside the loop
For example:
This code works:
class Array {
public static void main(String args[]) {
int[] array = {1,2,3,4,5,6,7,8,9,10};
for (int iterator : array) {
System.out.println(iterator);
}
}
}
This code does not work
class Array {
public static void main(String args[]) {
int[] array = {1,2,3,4,5,6,7,8,9,10};
int iterator;
for (iterator : array) {
System.out.println(iterator);
}
}
}
Someone please give me some insight about the topic and also if someone can explain about the memory mapping of for each loop it will be usefull. Thanks in advance
It's just how the enhanced for loop is defined. The variable that receives each value must be declared in the loop header.
The reason is that a separate variable is created for each loop iteration. In the linked spec section, see the example of what the enhanced for loop would look like if it were a simple for loop:
// Your enhanced `for` loop rendered as a normal `for` loop per the spec:
int[] array = {1,2,3,4,5,6,7,8,9,10};
{
int[] a = array;
for (int index = 0; index < a.length; index++) {
int iterator = a[index];
System.out.println(iterator);
}
}
Notice how iterator (not a great name for that variable) is recreated on each iteration. (It's conceptually similar for the other form of enhanced for dealing with an Iterable instead of an array.)
One advantage of it being a separate variable every time is that we can use final with it, which is useful particularly if we want to use its value in a lambda.
That also addresses your question about memory: As with any block, new stack space is allocated and used for the locals within the block. We have three levels of that in the above: The freestanding block wrapping the entire thing containing the notional a variable; the for statement itself containing index; and the body block containing iterator.
It's worth noting that the enhanced for could have been defined such that it let you optionally declare the value variable outside the loop, it just wasn't. It could have been defined such that if the variable were pre-declared, inside the loop iteration it would just do an assignment, not create a new variable and do an assignment. But it would have made it more complicated, and it already had the complication of needing to handle both arrays and Iterables. Apparently the cost of the complication wasn't considered worth the flexibility.
You are braking the syntax of enhanced loop. A compilable for each loop syntax is
EnhancedForStatement:
for ( {VariableModifier} **UnannType** VariableDeclaratorId : Expression ) Statement
https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14.2
Loop must know in it's type in it's own scope, since you breaking that, the error.
I'm trying to move my code from c# to java and it's the first time i'm trying to write java code.
Firstly i noticed that a List<> in c# is not as a list in java where i had to use an arrayList instead so i just changed
List<Instruments> instruments = new List<Instruments>();
to
List<Instruments> instruments = new ArrayList<Instruments>();
and that solved that.
Later on in my program i have a for loop which runs though the List (of an abstract "Instruments" class) and compares an enum (saved in .type) value which all the subclasses have. I:E
public static int HowManyOfType(InstrumentType TP)
{
int HowMany = 0;
for (int i = 0; i < instruments.Size(); i++)
{
if (instruments[i].type == TP)
HowMany++;
}
return HowMany;
}
However i'm getting the message "Array Type expected".
This problem wouldn't occur in c# because the property is stored in the abstract class and it would just do the comparison without needing to know the type of subclass that was stored.
I'm guessing that it's not that simple in java. Is there a was around this?
Thanks
Change this
if (instruments[i].type == TP)
to
if (instruments.get(i).type == TP)
Change your for loop to this.
for (Instruments eachInstrument : instruments) {
if (eachInstrument.type == TP) {
howMany++;
}
}
although without knowing what the data type of eachInstrument.type is, I can't be sure that it's correct to use ==. You may need to change this to eachInstrument.type.equals(TP).
If you are used to C# you might find lambdas in Java 8 more natural.
long howMany = instruments.stream().filter(t -> t.type == TP).count();
Unless the type is a primitive or an Enum you may need to use equals
long howMany = instruments.stream().filter(t -> t.type.equals(TP)).count();
Alright, I am not completely sure that I worded the title right, but I want to use an int variable to define another int to go through a method. In other words, I want to be able to have the int/name/thingy variable go through a ++ statement, and then the next variable would go through the method. Is this possible?
An int array might solve your problem. The array stores your ints ("variables"), another one runs throught the index (your ++ operation):
int[] values = loadValuesInArray(); // some magic to get the populated array
for (int i = 0; i < values.length; i++) {
myMagicMethod(values[i]); // calling the method with int values
}
If you need named variables, then you can use a map:
Map<String, Integer> variables = new HashMap<String, Integer>();
variables.put("a", 1);
variables.put("b", -10);
variables.put("c", 25);
myMagicMethod(variables.get("b")); // calls method with value from "variable" b
You can use reflection.
http://java.sun.com/developer/technicalArticles/ALT/Reflection/
http://www.java2s.com/Tutorial/Java/0125__Reflection/Catalog0125__Reflection.htm
or see to have an idea.
Setting variables by name in Java
You almost certainly want to be using something like a Map or List (essentially a dense map with a small positive int key).
If you don't need to create a new variable with a name, stored in another variable, then reflection is a way to go.
String varName = "x";
Point2D point = new Point(15, 2);
Integer val = (Integer)Point.class.getDeclaredField(varName).get(point);
assert val == 15;
You say "I want to use an int variable to define another int" do you mean something like
int a = 0; //declare a new variable a of type int and assign it to zero
a b = 0; //declare a new variable b of type a which is an int and assign it to zero
From what you said, that is what it appears you are saying. If that is the case, I do not think you can do that. My memory says that there is a method that allows you to determine the type of an object, but to use that as a declaration of another variable... I don't know if you can do that.
As an exercise (note that I am a programming student, but this is an exercise to satisfy my own curiosity, not for a graded assignment) in using instance variables, I would like to create an unspecified number of instances of a class and assign a unique name to each. My idea would be to make a loop such as:
int i=1;
while (! response.equals("quit")){
SomeClass object_i = new SomeClass();
i++;
...
}
This would allow the program to create as many instances of SomeClass as needed by the user, then be able to refer back to instance variables in each one such as:
for (i=1; i <= count; i++){
sum += object_i.nonStaticInstanceVariable;
}
There is a suggestion for unique identifier names using AtomicLong at this thread:
java for loop executes too fast gives System.currentTimeMillis() duplicate
but I am unsure of how I would refer to instance variables in particular objects created using this method. Can anybody suggest a way to do what I'm trying to do in Java?
Many thanks.
In your first for-loop, you're creating instances of SomeClass, but you're not doing anything with them. What you want to do is gather them up in some kind of collection, so you can refer to them later, like this:
int i=1;
List<SomeClass> classes = new ArrayList<SomeClass>();
while (! response.equals("quit")){
classes.Add(new SomeClass());
i++;
...
}
Now you can loop through your collection and do something useful with them:
for (SomeClass someClass : classes) {
sum += someClass.nonStaticInstanceVariable;
}
I would use a map and a universally unique identifier (UUID). See java.util.UUID for an example.
Map<UUID,SomeClass> map = new HashMap<UUID,SomeClass>();
for (int i=0;i<1000000;i++) {
UUID key = UUID.randomUUID()
map.put(key, new SomeClass());
}
Now if the user has a UUID then they can get a reference to the appropriate SomeClass
lol, you must really just be starting.
Read this- http://download.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
Most of what you have makes sense, but you need to do-
SomeClass myObject[i] = new SomeClass();
EDIT: Other people's options will work too, but you should learn to do it this way first.
You can't create instance variables at runtime (short of compiling and loading a new class)
Use an array or a Map for this
(Or use a dynamic language like Groovy that runs on the JVM, which internally will use a map-like structure)
I think you would just want to use some sort of collection such as an array or arraylist.
List list = new ArrayList();
int i=1;
while (! response.equals("quit"))
{ list.add(new SomeClass());
i++;
}
It could then be accessed by getting index in the ArrayList
list.get(index);
I have a recursive algorithm which steps through a string, character by character, and parses it to create a tree-like structure. I want to be able to keep track of the character index the parser is currently at (for error messages as much as anything else) but am not keen on implementing something like a tuple to handle multiple returned types.
I tried using an Integer type, declared outside the method and passed into the recursive method, but because it's final, recursive call increments are "forgotten" when I return. (Because the increment of the Integer value makes the passed-by-value object reference point at a new object)
Is there a way to get something similar to work which won't pollute my code?
Since you've already discovered the pseudo-mutable integer "hack," how about this option:
Does it make sense for you to make a separate Parser class? If you do this, you can store the current state in a member variable. You probably need to think about how you're going to handle any thread safety issues, and it might be overkill for this particular application, but it might work for you.
It's kind of a hack, but sometimes I use an AtomicInteger, which is mutable, to do things like this. I've also seen cases where an int[] of size 1 is passed in.
The current solution I am using is:
int[] counter = {0};
and then pass it to the recursive algorithm:
public List<Thing> doIt (String aString, int[] counter) { ... }
and when I want to increment it:
counter[0]++;
Not super elegant, but it works...
Integers are immutable, which means that when you pass it as an argument it creates a copy rather than a reference to the same item. (explanation).
To get the behavior you're looking for, you can write your own class which is like Integer only mutable. Then, just pass it to the recursive function, it is incremented within the recursion, and when you access it again after the recursion is over it will still maintain its new values.
Edit: Note that using an int[] array is a variation on this method... In Java, arrays are also passed by reference rather than copied like primitives or immutable classes.
You could just use a static int class variable that gets incremented each time your doIt method is called.
You could also do:
private int recurse (int i) {
if (someConditionkeepOnGoing) {
i = recurse(i+1);
}
return i;
}
To be honest I would recode the function to make it a linear algorithm that uses a loop. This way you have no chance of running out of heap space if you are stepping through an extremely large string. Also, you would not need to have a the extra parameter just to keep track of the count.
This also would probably have the result of making the algorithm faster because it does not need to make a function call for every character.
Unless of course there is a specific reason it needs to be recursive.
One possibility I can think of is to store the count in a member variable of the class. This of course assumes that the public doIt method is only called by a single thread.
Another option is to refactor the public method to call a private helper method. The private method takes the list as a parameter and returns the count. For example:
public List<Thing> doIt(String aString) {
List<Thing> list = new ArrayList<Thing>();
int count = doItHelper(aString, list, 0);
// ...
return list;
}
private int doItHelper(String aString, List<Thing> list, int count) {
// ...
// do something that updates count
count = doItHelper(aString, list, count);
// ...
return count;
}
This assumes that you can do the error handling in the public doIt method, since the count variable isn't actually passed back to the caller. If you need to do that, you could of course throw an exception:
public List<Thing> doIt(String aString) throws SomeCustomException {
List<Thing> list = new ArrayList<Thing>();
int count = doItHelper(aString, list, 0);
// ...
if (someErrorOccurred) {
throw new SomeCustomException("Error occurred at chracter index " + count, count);
}
return list;
}
It's difficult to know whether that will help without knowing more about how your algorithm actually works.