So, right after the public class declaration, I've declared an array as follows:
public String[] accept;
From here then, I'm looking to take user input to see how long this array should be - and following this, we'd enter into a loop to populate the array with Strings. I put the following into a method;
if (scanner.hasNextInt()) {
wcount = scanner.nextInt();
//create the array.
String accept[] = new String[wcount];
}
System.out.println(accept.length);
But unfortunately, no nice. Java returns with;
Exception in thread "main" java.lang.NullPointerException
Obviously, attempting to go straight into a for loop to populate the array, will also give the same results. At first glance, I'm assuming this has something to do with it being initialised as a public array outside of the method itself - but I'm honestly not too sure. Can anyone lend a hand on this?
You are declaring a new array in your if block, which is hiding your previously declared array. When the block exits, the variable goes out of scope and you get an NPE attempting to access the (unchanged) instance variable. Change your code to actually initialize your instance variable like so:
if (scanner.hasNextInt()) {
wcount = scanner.nextInt();
//create the array.
accept = new String[wcount];
}
System.out.println(accept.length);
You are recreating a new accept [] as local variable. Change your loop as below
if (scanner.hasNextInt()) {
wcount = scanner.nextInt();
//create the array.
accept = new String[wcount];
}
Change String accept[] to just accept within the if statement, you are redeclaring a new one within that scope, leaving the old one null.
String accept[] = new String[wcount];
declares a variable, and stores the reference to the new string array into it.
You probably want to use the previously declared variable instead. To do that, simply use assignment expression directly:
accept = new String[wcount];
Related
I'm a beginner in Java I have some questions regarding the enhanced for loop and string arrays.
In the source code below, I've been trying to change the contents of the arrays using the enhanced-for loops.
It seems that I can't change the contents in the the String array(arrString), but I don't know exactly why. (It works fine for StringBuilder objects.)
I am a bit confused because I could actually do operations like str1+=str2 and change the String contents (although this operation is done via StringBuilder class) in normal situations.
Can anyone point out why this is happening and if there's any misunderstanding on my part?
class EnhancedForTest{
public static void main(String[] args){
//StringBuilder
StringBuilder[] arrStringBuilder=new StringBuilder[]{new StringBuilder("Hello1"), new
StringBuilder("Hello2"),new StringBuilder("Hello3")};
for(StringBuilder e: arrStringBuilder){
e.append("!");
}
for(StringBuilder e:arrStringBuilder){
System.out.println(e);
}
//String
String[] arrString=new String[]{"Hello1","Hello2","Hello3"};
for(String s:arrString){
s+="!";
}
for(String s:arrString){
System.out.println(s);
}
}
}
The results are as follows(Sorry I didn't add the results!):
Hello1!
Hello2!
Hello3!
Hello1
Hello2
Hello3
P.S.: I've taken out the printing line as a new for loop, it still works for StringBuilder but not String
On each iteration of the for-each loop the variable obtains a reference to the corresponding element of the array. In the case of for(StringBuilder e:arrStringBuilder) on the first iteration a new variable e of type StringBuilder will point to the same object as arrStringBuilder[0]. Then you call append using this reference, which performs operations on the object pointed by both references e and arrStringBuilder[0]. On the next iteration e will be assigned reference to arrStringBuilder[1], but the changes made in arrStringBuilder[0] will stay.
In the case of for(String s:arrString) on the first iteration a new variable s will be created pointing to arrString[0]. However, when you do s += '!' you actually perform s = s + '!', so you assign to this temporary variable s a reference to the new String object, which will contain Hello1!. This new object, however, is not related in any way to the original arrString[0] object, and at the start of the next iteration is just discarded. Your loop works like this:
for(int i = 0; i < 3; i++) {
// Create a temporary variable which points to the same object as arrString[i]
String s = arrString[i];
// Create a temporary object which keeps the result of concatenation of s and '!'
String temporary = s + '!';
// Replace the reference stored in s with the reference to the temporary object
s = temporary;
// Now there is no connection between s and arrString[i]
// And here we just discard both temporary objects 's' and 'temporary'
// arrString[i] object remains unchanged.
}
e.append("!"); is a call to a method, whose specific purpose is to modify e.
s+="!"; is not a method call. It is exactly equivalent to this:
s = s + "!";
This does not alter the state of any object. It merely creates a new String object (that is, a String whose text value is the old value of s plus "!"), and assigns that to the variable s. You are changing what s holds, but you didn’t modify the original String object that s used to hold.
It turns out there are no methods of String which will modify the String object, because Strings are immutable, by design. On the other hand, the StringBuilder class exists specifically to create and work with changeable text values.
I am confused about how the array was assigned to any data, as the method meant to be a self contain
or I haven't understood a fundamental concept
// Craft stall stock and till program
import java.util.Scanner;
public class revisonTest {
public static void main(String[] args) // where program exicutes
{
final int numOFitems = 50;
String[] item = new String[numOFitems];
int [] broughtItem = new int[numOFitems];
int[] costItem = new int[numOFitems];
int COUNT = getDetail(item,broughtItem,costItem);
System.out.println(item[0]);
}
public static int getDetail(String[] name,int[] quantities,int[]cost)
{
int count =1;
int arrayIndex =0;
String answer = "";
while(!(answer.equals("Exit")))
{
answer = userInput("Item"+count+": ");
if(!(answer.equals("Exit")))
{
name[arrayIndex] = answer;
quantities[arrayIndex] = Integer.parseInt(userInput("How many "+name[arrayIndex]+" have you brought? "));
cost[arrayIndex] = Integer.parseInt(userInput("How much does a "+name[arrayIndex]+" cost? "));
count++;
arrayIndex++;
}
}
return count;
}
public static String userInput(String question)
{
Scanner sc = new Scanner(System.in);
System.out.println(question);
return sc.nextLine();
}
}
String[] item = new String[numOFitems];
This first makes a new treasure map named 'item'.
This makes a new treasurechest capable of containing numOFitems treasuremaps, and buries it in the sand. It is then filled with that many blank maps that lead to no treasure.
This updates your item treasuremap to point at this treasurechest-containing-maps.
getDetail(item,broughtItem,costItem);
This takes your treasuremap to the treasure-of-maps and makes a copy of it, and then hands the copy to the getDetail method. Your copy is unmodified and cannot be modified by getDetail... but that's just your copy of the treasure MAP, not the treasure. Note that getDetail calls this copy name and not item - which it is free to do.
(in getDetail) name[arrayIndex] = answer;
This is getDetail taking its name treasuremap (which is a copy of main's item map), follows the map, gets a shovel out, digs down, finds the treasure, opens it, finds the arrayIndexth map in it, pulls it up, and copies its answer map onto it.
Thus.. when main follows its copy of its map to the same treasure, same thing happens.
Of course, in java we use different jargon.
'treasure' -> 'object'
'treasuremap' -> 'reference'
'follow the map, dig down, open treasure' -> 'dereference'.
'create treasure' -> 'instantiate an object'
There are two different concepts here:
Allocating an array and assigning an array reference to a variable, and
Assigning values to elements in the array
In main, the new operation creates an array of a certain size, and assigns a reference to that array to the variable named item.
The call of getDetail(item,...) makes a copy of that reference (not the array itself) available to the method. Inside getDetail, this reference is stored in what is effectively a local variable, named name.
The loop inside getDetail is collecting answers (which are actually String references) and storing them in successive elements of the array that it knows as name and which the caller knows as item.
name[arrayIndex] = answer;
(Similarly for the other two arrays, of course)
In summary, getDetail is provided with an existing array, into which it writes values.
Incidentally, if the user types too many answers (more than name.length) you'll run off the end of the array, and get an 'index out of bounds' exception.
A String in java is considered a non-primitive data type. So when you created your item array using:
String[] item = new String[numOFitems];
You actually created an empty array of String objects. Based on your code the array has 50 empty spaces where you can store data.
The next part of your code is designed to get input from the user and fill those arrays:
int COUNT = getDetail(item,broughtItem,costItem);
Note: getDetail() never returns the item[] array, so how do you access the data?
When you pass your item array as an argument to the getDetail() method, you are actually passing that array as a reference.
In Java, non-primitive data types are passed as reference. This means that instead of sending the data to the getDetail() method, your actually sending information about where the data is located in memory.
Within your getDetail() method you can manipulate the data and the changes will be reflected on the original array without having to return it.
That is the reason why your print statement shows data in the array:
System.out.println(item[0]);
Any changes made within the getDetail() method, to the array, automatically appear on the original data source.
what is wrong with my code?
in the main method i am doing this:
int [] test=new int[48];
test=etable(Right[]).clone();
What i want is, that the 'test' array is exactly the same like the output of the 'etable' method.
my method called 'etable':
public static int [] etable(int [] right){
int [] blabla=new int[48];
...
return blabla[]
}
Thanks for your advise
what is wrong with my code?
This line is a compilation error:
test = etable(Right[]).clone();
If right (or Right) is a variable (declared with type int[]), then you should write the method call like this:
test = etable(right).clone();
If Right is a type, then that is not the correct syntax for creating an array. (And judging from how you have written the etable method, you should not be passing it a new array.)
The second problem is that this sequence doesn't make sense:
int test[] = new int[48];
test = etable(...).clone();
You are allocating an array of 48 elements ... and then throwing it away by assigning a different array reference to the test variable.
The third problem is that the clone() is most likely redundant anyway. Your etable method is allocating a new array (in blabla) and returning it. The calling code is then copying the new array. Unless the etable saves the reference to the blabla array somewhere, the copying step doesn't achieve anything.
The final problem is that if Right really is a variable name, then that is a serious Java style violation. In Java a variable name should NOT start with an upper-case letter.
Use for instance Arrays.copy():
int[] tmp = etable(whatever);
int[] test = Arrays.copy(tmp, 0, tmp.length);
As to your original code, this, for instance:
test = ebtable(Right[]).clone();
is not legal Java (what is Right anyway?).
Here is the thing- my Main method only calls InitGui. Inside the whole class (basically the whole file, i have the InitGui method and a few public static gui objects. One of the objects is actuall an array
public static JButton Keys[] = null;
And I have a method called placeKeys that gets the location for each JButton "Keys" and places it on the panel. The whole code works when I do not use this method, basically instead of for i=0 to whatever, I want just call placeKey(arguments here...) instead of
for each jButton to be placed like this
for i=0 to whatever
Keys[i] = new JButton(jBStringArray[i]);
Keys[i].setLocation(2 + i*kSize,2+row*50);
Keys[i].setSize(50, kSize);
keyboardPane.add(Keys[i]);
I have the method written down but it reports a pointer error at the placeKeys when it tries to access the Keys[] , meaning the first line of the method
Hope you understood me
Before your for loop (either when you declare it, or, if you rely on the null check, just before the for loop) you need to create the array with Keys = new JButton[whatever+1];. Oh and please start your variable names with a lowercase letter - it's the universally-accepted thing to do.
//assuming jBStringArray is already defined here
public static JButton Keys[] = new JButton[jBStringArray.length];
Basically I have a variable, zlort = one;
I want to concatenate the value of zlort into a variable (object reference) name.
Like
BankAccount Accountzlort = new BankAccount;
I want the zlort in Account.zlort to actually be the replaced with value of zlort (one--meaning I want the value to be Accountone), and not zlort itself.
Is it possible to do this?
Thanks!
No you can't, but you might put the instance in a map:
Map<String,BankAccount> map = new HashMap<String,BankAccount>();
map.put("Account" + zlort, new BankAccount());
If you mean dynamically choosing the name to assign a variable to, then no.
You could use a HashMap to achieve the same effect.
It is not possible to change the name of a variable at runtime. That would lead to extreme security and stability problems when dealing with any real-world application.
However, as the two answers here have mentioned, a HashMap might acheive what you are looking for. (See the javadoc!!)
A HashMap (or any other map, for that matter) maps a Key to a Value. The concept is similar to a variable, which is a name -> value mapping. The only difference is that variables are part of the actual program code, which is effectively unmodifiable after compiling. A Map is a data structure that can be modified by the running program. This allows you to freely add key-value pairings to it.
Note that in Java, type-safety is encouraged through the use of Generics. Basically this ensures that the key can only be of one type (e.g. String) and the value can be of only one type (BankAccount). A thorough coverage of Generics can be found here.
You would declare this as follows:
Map<String, BankAccount> accounts = new HashMap<String, BankAccount>();
And then to add a key-value pair to the map, you would use the put() method (which 'puts' a value into the map, associated with a key)
String key = "Key"
BankAccount value = new BankAccount();
accounts.put(key, value);
To retrieve it, you would use the get() method.
BankAccount retrievedValue;
retrievedValue = accounts.get(key);
After reading the explanations in your comments, the fact that you can't use an array but can use an `ArrayList'...
Rather than creating a new variable name (or array element, or map value) for each BankAccount, you can probably use scope to your advantage.
Scope is the concept that a reference to a variable only has meaning within a certain part of code. If you declare a variable inside a method, that variable can only be seen within that method. A variable declared within a block (a loop, if statement, etc ) can only be seen from within that block.
Class fields have a different kind of scoping that can be adjusted with keywords (see here).
For example:
public class ScopeExample
int classInt = 10;
public void method() {
int methodInt = 0; // This integer can only be seen by code in
// this method
}
public void method2() {
//doSomething(methodInt) // This line won't compile because i is
// declared in a different method!
doSomething(classInt); // This line will compile and work
// because x is declared in the class that
// contains this method.
int index = 0;
while (index < 3) {
int whileInt = index; // This integer can only be seen from within
// this while loop! It is created each
// loop iteration.
doSomething(whileInt);
}
doSomething(whileInt); //This line won't work, whileInt is out of scope!
}
public doSomething(int a) {
System.out.println(a);
}
}
SO! If you create a BankAccount object within the loop, you don't have to worry about creating a new name for the next one. Each time the loop iterates it will become a new object (when you create it).
If you have to store it, you definitely will need to use an array or other data structure (ArrayList!).
Building on the idea of scope, you -can- have the same variable name for each new BankAccount. A variable reference name isn't guaranteed to be paired with the object that it refers to. That is a convenience to the programmer, so you don't have to know the exact memory address it is being stored in.
For example:
public static void main(String[] args) {
Object o;
int i = 0;
while (i < 5) {
Object reference = new Object(); // Create a new Object and store
// it in 'reference'
o = obj; // The Object 'o' now refers to the object in 'reference'
i++;
}
System.out.println(o); // This should print information about the
// LAST object created.
}
The new Object created in the loop does not belong to 'obj'. You as a programmer use 'obj' to point to the Object. The program doesn't really know what obj means, other than the fact that it points to the Object you just created.
Finally, you can use this along with an ArrayList to make your life easier.
public static void main(String[] args) {
// Our new ArrayList to hold our objects!
ArrayList<Object> stuff = new ArrayList<Object>();
int i = 0;
while (i < 5) {
Object obj = new Object(); // Create an object and make obj point to it.
stuff.add(obj); // Put "the object that 'obj' points to" in 'stuff'.
i++;
}
// This loop goes through all of the Objects in the ArrayList and prints them
for (int index = 0; index < stuff.size(); index++) {
System.out.println(stuff.get(i)); // This will print a single
// object in the ArrayList each time.
}
}