Get information outside a loop - java

I've a problem. I want to fill an array with objects containing different Informations.
here is my loop
public FileRecord [] calcPos() throws IOException{
for (int i = 0; i < getEFSFATmaxRecords(); i++){
int blockNumber = i/5;
int recordOffset = i%5;
pos = (recordOffset*100+(getFsatPos() + 512 + 512*blockNumber));
FileRecord rec = new FileRecord(pos,getHeader());
array = new FileRecord[header.getMaxFileRecords()];
array[i] = rec;
System.out.println("FileName: " + array[i].getFileName());
}
return array;
}
It should make different objects of FileRecord. The position depends on the running variable i. t
Then the loop stores everything in the array and returns the array. Ive declared array as a global variable in this calss so I thought the changes inside the loop would directly affect the global array. But it doesnt work. what I'm doing wrong?

Within the array you are doing:
array = new FileRecord[header.getMaxFileRecords()];
This will re-create the array every interation and you'll lose the records stored in it.
You'll need to do this before the loop

You are re initializing your array in every iteration. Below is a correct version of the code you want:
public FileRecord [] calcPos() throws IOException{
FileRecord[] array = new FileRecord[header.getMaxFileRecords()];
for (int i = 0; i < getEFSFATmaxRecords(); i++){
int blockNumber = i/5;
int recordOffset = i%5;
pos = (recordOffset*100+(getFsatPos() + 512 + 512*blockNumber));
FileRecord rec = new FileRecord(pos,getHeader());
array[i] = rec;
System.out.println("FileName: " + array[i].getFileName());
}
return array;
}
As vogel says if the header.getMaxFileRecords() changes within the loop then your array may run out of bound.
Solution: An ArrayList should work.

The problem is that you do:
array = new FileRecord[header.getMaxFileRecords()];
INSIDE the method every time it is invoked (in fact, inside the loop!).
This way, you are "setting" a new FileRecord[] object to the variable (and even worse, this happens many times in your method as the initialization is done in the loop).
Each time this initialization happens, the variable "points to the new FileRecord[] object allocated in memory. The Object that was "pointed to" by array before is not used anymore, and will be destroyed, the when is responsibility of the garbage collector.
(http://javabook.compuware.com/content/memory/how-garbage-collection-works.aspx).
In simple words, you are "recreating" the array again and again inside your loop.
Initialize the object only ONCE before using it in your method (for example in class constructor or in main, before using it in a sense).
Generally, I suggest that you don't use global variables. Search more on class encapsulation, a very important Object-Oriented Programming principle:
(http://www.tutorialspoint.com/java/java_encapsulation.htm).

Related

How to add a string into a StringArray [duplicate]

This question already has answers here:
Java: how to initialize String[]?
(11 answers)
Closed 12 months ago.
I've already created the whole code, but i don't know how to add a String to a String array.
here's my code:
**CandidateDAO candidatedao = new CandidateDAO();
String fill = null;
CandidateReport[] candidatesReports = candidatedao.getAllCandidates();
String [] newArray = ;
for(int i = 0; i < candidatesReports.length; i++) {
fill = candidatesReports[i].getCandidateId() + ":" + this.calculateGrade(candidatesReports[i]);
}
return newArray;*****
String [] newArray = ;
This is obviously wrong. To create an array of any type, you need to first instantiate it correctly. To do this, you need to set its size. The reason why you need to set its size is because arrays are allocated in memory in contiguous locations. This means that each index location is right next to another.
String [] newArray = new String[SOME_SIZE];
The SOME_SIZE is a value based on whatever you need. In your case, you have another array, candidatesReport, that could be used to determine the size (length) of your given array.
String [] newArray = new String[candiatesReport.length];
Now that is done, you need to set the value in the array.
newArray[i] = ...;
For you, this is done inside the loop...
for(int i = 0; i < candidatesReports.length; i++) {
newArray[i] = candidatesReports[i].getCandidateId() + ":" + this.calculateGrade(candidatesReports[i]);
}
UPDATE:
This problem is mainly to display some information contained in an array of CandidateReport objects by collecting data from each instance and concatenating it as a String. Not knowing about the internals of the aforementioned class, I believe this problem is better served by overwriting the Object's class toString() method in the CandidateReport class, so when objects of this type are printed, the output comes the way we want it. Otherwise, every class that wishes to display CandidateReport contents, it will have to repeat this same code over and over again. So here is a simple case for overriding toString() method.
public class CandidateReport {
// rest of code omitted
#Override
public String toString() {
return candidateId + ":" + grade;
}
}
If the grade needs to be calculated, you will be better off putting that logic in a utility class where you could call some static method to return the calculation. For example:
return candidateId + ":" + CalculatorUtilities.calculateGrade(grade);
The point of the matter is that each class should override the Object#toString() method to provide a default string representation of objects of a given type. If you do this, you won't need the String array at all. But, if you still feel it is necessary to capture this data in an String array, your code will be much simpler because of the overridden toString() method.
for(int i = 0; i < candidatesReports.length; i++) {
newArray[i] = candidatesReports[i].toString();
}

Removing null values from array and getting it from the method in Java

I'm trying to remove null values from an array, and returning them to do some other stuff with the new values. However, I'm confused about how to get the updated array.
This is the null removal code.
String[] removeNull(String[] nullArray) {
int nullCounter = 0;
//checking if any is null
for(int i = 0; i < nullArray.length; i++) {
if(nullArray[i]==null) {
nullCounter++;
}
}
String[] noNulls = new String[nullArray.length-nullCounter];
if(nullCounter>0) {
//make a non null array
for(int i = 0, j = 0; i <noNulls.length; i++) {
if(nullArray[i]!=null) {
noNulls[j] = nullArray[i];
j++;
}
}
}
return noNulls;
}
I'm pretty sure that is already correct (Please correct me if I'm wrong). Then, I called it inside a constructor.
public theBoundary(String[] bounds){
removeNull(bounds);
}
After I called removeNull(bounds), will the value of the new array be stored in the array bounds? Or will it be stored in the array noNull? I can't seem to find where the new values are stored.
Thank you, and please tell me if there are mistakes. I've been going around this for half an hour now.
Note: If possible, please don't give me answers that include importing something else. Vanilla Java would be preferred.
removeNull() returns the array noNulls, created inside the method. Currently, in theBoundary(), you simply call removeNull(bounds), but do not assign it to a variable. The newly created null-free array is created, not assigned, and immediately garbage collected.
If you wish to do something with your non-null-containing array (which I assume you do), do this:
public theBoundary(String[] bounds) {
String[] withoutNulls = removeNull(bounds);
doSomething(withoutNulls); // whatever you need here
}
Note, unless you really have to use an array, consider using a List or even a Stream.
List example:
List<String> list = ... // from somewhere else
list.removeIf(s -> s == null);
doSomething(list);
Stream example:
Stream<String> stream = ... //from somewhere else
stream.filter(s -> s != null);
doSomething(stream);
EDIT
Even if you do really need arrays, the following will also work:
String[] noNulls = (String[]) Arrays.stream(inputArray).filter(Objects::nonNull).toArray();
I don't think there is any need to iterate the array twice!
You can instead use a stream on array and filter the indexes without that are NOT NULL.
Also, you can do this without needing to create the removeNull method, and do this directly in your theBoundary method.
Here is how your code will look like:
String[] arrayWithoutNull = Arrays.stream(bounds).filter(Objects::nonNull).toArray(String[]::new)
I hope this solves your problem.
Do you mean this?
public theBoundary(String[] bounds){
String[] cleanedBounds = removeNull(bounds);
}
You are not doing it inplace so you need to assign it back to a new array

text based undo function in java

I'm trying to figure out how to get a undo function for a small maze game. First I worked out a way to do this by checking what the last direction was and just going back in the opposite direction. But this code was getting way too long since I also had to track back possible item pickups or hidden walls etc.
Background info on the code: I use a String[][] to store the maze as this was the easiest. I use an Arraylist<String[][]> to store all the strings.
After each step the player takes I save the String[][] array to the arraylist. When the player say undo I look at the second last String[][] in the arraylist and want to set the String[][] back to this. But the currentPos never seems to get updated. I'm not sure where the problem lies.
if (direction.equals("north")) {
if (currentPos[i - 1][j].equals("---")) {
continue;
} else {
currentPos[i][j] = " ";
currentPos[i - 2][j] = "P";
break;
}
}
if (direction.equals("undo")) {
currentPos = history.get(history.size()-2);
history.remove(history.size()-1);
break;
}
Without understanding the way you are setting history, I've made the assumption from your question that you are simply adding the current map to the history list. If you aren't careful, you will be simply adding the same Object, populating the history with multiply Object references to the current map state. This would have the effect you are observing with the state not changing, because you the history only contains a reference to the most recent map (Not storing any actual history).
To obtain the value from an Object, you typically need to clone the object (invoking the clone() method). However, cloning a 2-dimensional array is somewhat problematic. Invoking the clone() method on a 2-dimensional array "shallow" clones the object, essentially only cloning the first dimension while leaving the second as a reference to the same object (The reason for this is that the first 1-dimension of the array holds a reference to the second 1-dimension). Changing the value on a shallow copied object will change the value of the original and vice-versa, not what you want if you want to keep the Objects distinct.
To create two distinct objects, you will need to perform a "deep" clone, which can be easily implemented in a helper method. The below code illustrates the importance of ensuring you fully clone the object before storing it in the history list.
public static void main (String args[]) throws Exception {
ArrayList<String[][]> list = new ArrayList<>();
String[][] shallowClonedMap = new String[1][1];
String[][] deepClonedMap = new String[1][1];
shallowClonedMap[0][0] = "Old";
deepClonedMap[0][0] = "Old";
list.add(shallowClonedMap.clone());
list.add(deepClone(deepClonedMap));
shallowClonedMap[0][0] = "New";
deepClonedMap[0][0] = "New";
list.add(shallowClonedMap.clone());
list.add(deepClone(deepClonedMap));
for (String[][] item : list) {
System.out.print(item[0][0]);
}
}
public static String[][] deepClone(String[][] arry) {
if (arry == null) {
return null;
}
String[][] clone = new String[arry.length][];
for (int i = 0; i < arry.length; i++) {
clone[i] = arry[i].clone();
}
return clone;
}
The output for executing this code is : NewOldNewNew whereas the "intended" output is "OldOldNewNew". From this you can see the shallowClonedMap was updated to "New" even after being cloned and added to the list.

Specific NullPointerException Java

i have short question, tell me just why first example don't work and second works.
Code before examples:
Tiles[] myTiles = new Tile[23];
number = 1;
First Example:
for(Tile tile : this.myTiles) {
if (number != this.myTiles.length) {
tile = new Tile(number, getResources().getColor(R.color.puzzle_default));
number++;
}
}
Second Example:
for(Tile tile : this.myTiles) {
if (number != this.myTiles.length){
this.myTiles[number-1] = new Tile(number, getResources().getColor(R.color.puzzle_default));
number++;
}
}
If i use code below in other method in class
this.myTiles[0].getNumber();
It's NullPointerException.
But with Second Example it nicely works.
I really don't know why. Thanks for any response
The first loop makes a copy of each object and is equivalent to
for (int i=0; i < myTiles.length; i++) {
Tile tile;
...
tile = new Tile(...); // set local reference only
}
As elements in an Object array are null by default these would remain unassigned outside the scope of the loop. The original elements of the myTiles remain at their default null values
The for each loop uses an Iterator internally to fetch items from the collection and return you a new reference to a local variable containing each element - overwriting this reference is completely useless, as it is only valid for one for-loop and will be replaced on the next.
"Internally", your first loop would translate to
for (Iterator<Tile> iterator = myTiles.iterator(); iterator.hasNext;){
Tile tile = iterator.next();
tile = new Tile(number, getResources().getColor(R.color.puzzle_default));
number++;
}
In Java, there is no such thing as manipulating a pointer directly. Any time you get a reference to an object, you are getting a copy to a reference, like a pointer to a pointer. For this reason if you do something like:
String s = "hello";
modify(s);
System.out.println(s); // still hello!
void modify(String s){
s = s + " world";
}
You can't actually change the original reference s because the function is manipulating a copy to that reference. In the example above you would need something like this:
String s = "hello";
s = modify(s);
System.out.println(s); // prints 'hello world'
String modify(String s){
return s + " world";
}
The same happens in your for comprehension. The variable tile is bound to the loop and is a copy of a reference in the array. The original reference (the array at the given position) can't be changed directly this way. That's why you need to call directly:
myTiles[i] = // something
Read this article for more information.
So the idiomatic way of modifying an array in java is something like:
for(int i = 0; i < myTiles.length; i++){
myTiles[i] = new Tile(...); // directly reassigning the reference in the array!
}

Why do I get a "duplicate local variable" error?

I have a loop in which I calculate a value and add it it a list. So, I do something like that:
x = getValue()
values.add(x)
while (true) {
x = getValue();
values.add(x)
}
I found out that this approach does not work since I add the same instance to the list. In more details, in every cycle of the loop I re-assign a new value to the x and doing so I change values of all elements that were already added to the list (so in the end I get a list of identical elements).
To solve this problem I did the following:
x = getValue();
Integer[] valueToAdd = new Integer[n];
for (int i=0; i<n; i++) {
valueToAdd[i] = x[i];
}
while (true) {
x = getValue();
y = new Integer[n];
for (int i=0; i<n; i++) {
valueToAdd[i] = x[i];
}
values.add(valueToAdd)
}
In this way I wanted to create a new instance every time want to add a value to the list. But it does not work since I get a duplicate local variable error.
It is also strange to me that I do not have this error if I declare the same variable many times in the loop. The problem appears only if I first declare a new variable outside the loop and then also in the loop.
Is there a way in Java to re-use the same name for different instances?
ADDED
I need to clarify some issues. I did not show all the code. I have the break command in the loop (when a new value cannot be generate, I exit the loop). x and value have Integer[] type.
ADDED 2
Since it was mentioned that the problem can be in the getValue() I need to in more details here. Actually I do not have getValue() in my code (I used getValue() here to make my example shorter). In my code I had:
Integer[] x = new x[n];
while (true) {
for (int i=0; i<n; i++) {
x[i] = y[i];
}
values.add(x)
}
And it did not work since in my values list I had identical elements (and I know that in the loop on every cycle x had a new value).
ADDED 3
Why all elements of my list seems to be the same?
Your problem is not what you think it is. For example take a look at this simple program:
String x = null;
List<String> l = new ArrayList<String>();
for (int i = 0; i < 10; i ++) {
x = String.valueOf(i);
l.add(x);
}
System.out.println(l);
It prints the numbers from 0 to 9. This is because java is pass-by-value (check here). You are not passing the reference to x, you are passing the value of x (in the add method).
So the problem lies in the getValue() method, which returns the same object.
Update: Now the question makes more sense. You are working with the same object x everytime, and just changing its state. In order to put different values just move the declaration inside the loop:
while (true) {
Integer[] x = new x[n];
...
}
If you need it outside the loop, well, simply use another variable there. It does not have to be named x. Since you won't be using it inside the loop anyway.

Categories