A while back, I was working on a program that hashed values into a hashtable (I don't remember the specifics, and the specifics themselves are irrelevant to the question at hand). Anyway, I had the following code as part of a "recordInput" method:
tempElement = new hashElement(someInt);
while(in.hasNext() == true)
{
int firstVal = in.nextInt();
if (firstVal == -911)
{
break;
}
tempElement.setKeyValue(firstVal, 0);
for(int i = 1; i<numKeyValues;i++)
{
tempElement.setKeyValue(in.nextInt(), i);
}
elementArray[placeValue] = tempElement;
placeValue++;
} // close while loop
} // close method
This part of the code was giving me a very nasty bug -- no matter how I finagled it, no matter what input I gave the program, it would always produce an array full of only a single value -- the last one.
The problem, as I later determined it, was that because I had not created the tempElement variable within the loop, and because values were not being assigned to elementArray[] until after the loop had ended -- every term was defined rather as "tempElement" -- when the loop terminated, every slot in the array was filled with the last value tempElement had taken.
I was able to fix this bug by moving the declaration of tempElement within the while loop. My question to you, Stackoverflow, is whether there is another (read: better) way to avoid this bug while keeping the variable declaration of tempElement outside the while loop.
Why would you want to keep the variable declaration outside the while loop? Anyway, you can, as long as you assign it to a new hashElement each time:
hashElement tempElement;
while (/*...*/) {
tempElement = new hashElement();
//...
It's certainly not "better" though. Scope your variables as narrowly as possible, in general.
This is not about declaration of the variable, but about the objects you create. Arrays in java only hold references to objects, so if you actually want to have distinct objects in the array, you need to create them with new somewhere in the loop.
tempElement = new WhateverClass();
Element tempElement;
while(condition){
tempElement = new HashElement();
//do more stuff
elementArray[index] = tempElement;
}
Related
In Java it is possible to declare a variable in the initialization part of a for-loop:
for ( int i=0; i < 10; i++) {
// do something (with i)
}
But with the while statement this seems not to be possible.
Quite often I see code like this, when the conditional for the while loop needs to be updated after every iteration:
List<Object> processables = retrieveProcessableItems(..); // initial fetch
while (processables.size() > 0) {
// process items
processables = retrieveProcessableItems(..); // update
}
Here on stackoverflow I found at least a solution to prevent the duplicate code of fetching the processable items:
List<Object> processables;
while ((processables = retrieveProcessableItems(..)).size() > 0) {
// process items
}
But the variable still has to be declared outside the while-loop.
So, as I want to keep my variable scopes clean, is it possible to declare a variable within the while conditional, or is there some other solution for such cases?
You can write a while loop using a for loop:
while (condition) { ... }
is the same as
for (; condition; ) { ... }
since all three bits in the brackets of the basic for statement declaration are optional:
BasicForStatement:
for ( [ForInit] ; [Expression] ; [ForUpdate] ) Statement
Similarly, you can just rewrite your while loop as a for loop:
for (List<Object> processables;
(processables = retrieveProcessableItems(..)).size() > 0;) {
// ... Process items.
}
Note that some static analysis tools (e.g. eclipse 4.5) might demand that an initial value is assigned to processables, e.g. List<Object> processables = null. This is incorrect, according to JLS; my version of javac does not complain if the variable is left initially unassigned.
No it's not possible.
It doesn't really make too much sense either: unlike a for loop where you can set up the initial state of the "looping variable", in a while loop you test the value of an existing variable, akin to the conditional check of the for loop.
Of course, if you're concerned about variables "leaking" into other parts of your code, you could enclose the whole thing in an extra scope block:
{
/*declare variable here*/
while(...){...}
}
Alternatively, convert the while loop into a for loop.
Make a do/while:
String value;
do {
value = getValue();
...your processing
} while (value != null && !value.isEmpty());
Is this usage of elements of an ArrayList:
for(int i=0; i<array_list.size(); i++){
Object obj = array_list.get(i);
//do **lots** of stuff with **obj**
}
faster than this one:
for(int i=0; i<array_list.size(); i++){
//do **lots** of stuff with **array_list.get(i)**;
}
It depends on how many times array_list.get(i) is called in the second code. If it is called only once, there is no difference between both methods.
If it's invoked multiple times, saving the value in a variable may be more efficient (it depends on the compiler and the JIT optimizations).
Sample scenario where the first method may be more efficient, compiled using Oracle JDK's javac compiler, assuming the list contains String objects:
for(int i=0; i<array_list.size(); i++){
String obj = array_list.get(i);
System.out.println(obj);
if(!obj.isEmpty()) {
String o = obj.substring(1);
System.out.println(o + obj);
}
}
In this case, obj is saved as a local variable and loaded whenever it is used.
for(int i=0; i<array_list.size(); i++){
System.out.println(array_list.get(i));
if(!array_list.get(i).isEmpty()) {
String o = array_list.get(i).substring(1);
System.out.println(o + array_list.get(i));
}
}
In this case, multiple invokation for List.get are observed in the bytecode.
The performance difference between getting once and a local variable is almost always neglible. But... if you insist on doing it the hardcore way, this is the fast way to go:
ArrayList<Object> array_list = ...
// cache list.size() in variable!
for (int i=0, e=array_list.size(); i < e; ++i) {
// get object only once into local variable
Object object = array_list.get(i);
// do things with object
}
It caches the lists size into a local variable e, to avoid invoking array_list.size() at each loop iteration, as well as each element in the loop to avoid get(index) calls. Be aware that whatever you actually do with the objects in the loop will most likely be by orders of magnitude more expensive than the loop itself.
Therefore, prefer code readability and simply use the advanced for loop syntax:
ArrayList<Object> array_list = ...
for (Object object : array_list) {
// do things with object
}
No hassles, short and clear. Thats worth far more than a few saved clock cycles in most cases.
I'm having some difficulty with this for-loop in java:
public String[] geefAlleTemplateNamen(String[][] templateLijst){
for(int i = 0; i < templateLijst.length; i++){
String lijst[] = {templateLijst[i][0]};
}
return lijst;
}
When i execute the program, i get the following error:
Mailmatcher.java:39: error: cannot find symbol
return lijst;
^
symbol: variable lijst
location: class Mailmatcher
1 error
I think this is because 'lijst' is declared inside the for loop, so it's unknown outside it, although i think i know what the problem is, i've got no idea how to solve this.
Any ideas would be appreciated!
I used the search allready, but didn't realy find something, this is a school project, so i don't expect pre-made answers.
Thank you!
You have to declare the lijst[] outside of the loop and fill the array within the loop:
String lijst[] = new String[templateLijst.length];
for(int i = 0; i < templateLijst.length; i++){
lijst[i] = templateLijst[i][0];
}
return lijst;
To add to the answer from kocko, it's because the scope of the list is confined to within the loop. Which will cause two problems,
The list gets redeclared as a new empty list for each iteration of the loop (wiping out any previously stored data)
The return is outside of the loop, so it can't access the list, it pretty much no longer exists once your code completes the loop and moves on.
So yes, declare the list before the loop.
Recursion is a new practice for me and I am trying to get better at it and understand how the methods return. I have the following program but am unfailiar with how to use the this keyword. Can you please review the code and walk me through the program showing the values held by the variables as the methods execute?
I have tried numerous things to determine how the value answer in the compute method holds 14 after execution can anyone walk me through the first few recursive calls so I can try and figure out the rest?
public class Recurs1 {
public static void main (String [] arg) {
Recurs1 r = new Recurs1();
r.compute();
}
public void compute() {
int [] stuff = {1, 2, 3, 4};
int answer = this.go(stuff, 0);
System.out.println("The answer is " + answer);
}
private int go(int[] numbers, int spot) {
if (numbers.length == spot) return spot;
int value = this.go(numbers, spot + 1 );
return value + numbers[spot];
}
}
Ok so a few things I notice here:
The purpose of go() seems to be calculating the sum of the numbers in the array. If this is the case, your method should look like this:
private int go(int[] numbers, int spot) {
if (numbers.length - 1 == spot) return numbers[spot];
int value = this.go(numbers, spot + 1 );
return value + numbers[spot];
}
This is because numbers.length in this case will return 4, but the last element in this array is at index 3 (arrays are 0-indexed).
This way, when the function is called with the second parameter set to 3, it will return the value of the last element in the array and then the code will "bubble up" (as I like to call it) and calculate the sum of the elements by subsequently returning the current summed value + the value of the current call.
As for your problem with the this keyword, it's actually very simple. this always refers to the current class instance your code is in. In this case, you create a Recurs1 instance called r in your main function so whenever you call a method on that particular object, the this keyword used in those methods will refer to r. If you created multiple Recurs1 objects (each with potential different internal states) in your program, their respective this references would always point to themselves allowing you to access their member variables and methods.
Hope that helps and good luck, recursion is usually what most people have trouble getting their heads around at first but once you get used to it it's pretty cool!
OK so this is not an answer to your question per se, more like a lesson in recursion.
Keep in mind I have never tried to to do this with a java class.
Recursion means a function that calls itself repeatedly until a answer has been reached, or your function detects you are running out of stack space.
You first step into the function determines if you will call yourself.
When you call yourself you will push a new copy of the data onto the stack and begin executing. I think in the case of java you will allocate a new object into the heap ( don't quote me on this ) and each invocation will have a new set of variables that get populated with new values.
As you recurse deeper and deeper you simply allocate new copies of the object until you find the answer or run out of memory.
If you find the answer you then return the result to the previous level in the stack of objects eg:
int foo(int i ){
if(some condition){
return foo(i);
} else
return i
}
as You can see if the condition tests true the foo() keeps getting called. Now at each call, the variables of foo() are saved for as many levels deep as you go. If the condition tests false then each instance of foo() returns to the previous until you are at the original invocation of foo() which then returns to the caller of foo().
Clear as Mud?
I have a problem where I retrieve and element from a list (list1), and modify one of the parameters in the element and then add it to another list (list2). When I do this to the final item in list1, it will sometimes modify the parameters of the elements in list2.
This function is called once per generation, but it is not until about the 8th generation when I start to see this happen. It has affect anywhere from 2 to 16 elements in list2.
Any ideas where my screw up might be? Here's a block of code I wrote to illustrate the problem. The problem occurs in the section where I check count==0.
public void sampleCode (List list) {
List differentList = new ArrayList();
Individual element;
Individual differentelement;
int i = 0;
int count = 0;
for(i = 0; i < list.size(); i++) {
element = (Individual) list.get(i) ;
// does some checking to see if this meets criteria
// this is sorta pseudo code
if(probability == true) {
element.setDoMutation(true);
count++;
}
//always add this element to differentList
//even if no changes are made to the element
differentList.add(i,element);
}
//need to make sure one elements has mutation=true;
if(count == 0) {
differentelement = (Individual) list.get((list.size()-1));
//setting this element field changes the contents of
//different list.
differentelement.setDoMutation(true);
differentList.set((list.size()-1), differentelement);
}
}
In Java, a variable doesn't hold an object. It holds an object reference (i.e. a pointer to an object). Getting an object fom a list and putting it in another list doesn't make a copy of the object. Both lists simply have a pointer to the same object. So, of course, if you modify the contents of the object, both lists will have the object modified.
Side note: You should use parameterized types (i.e. List<Individual> rather than List), and avoid declaring variables at the beginning of your methods as you would do in C. Only declare a variable when you need it. This will make the code much clearer, and reduce the scope of your variables.
Are you sure that the block
//need to make sure one elements has mutation=true;
if(count == 0) {
differentelement = (Individual) list.get((list.size()-1));
//setting this element field changes the contents of
//different list.
differentelement.setDoMutation(true);
differentList.set((list.size()-1), differentelement);
}
has to be inside the loop
for(i = 0; i < list.size(); i++) {
...
}
I suspect it has to be moved after the loop in order to work correctly.