I'm getting a null pointer exception on the following code (part of a larger program - the exception is thrown on the line where "add" is called).
public class A
{
static ArrayList<Integer> sets[];
public static void main(String[] args)
{
sets = new ArrayList[5];
sets[0].add(1);
}
}
I also do not understand why the compiler is requiring me to make any class level variables static (e.g. the ArrayList). As far as I can tell, these things shouldn't be in a static context (in terms of coding practice, not compiler problems) and yet the compiler is requiring it.
Thanks in advance.
sets = new ArrayList[5];
Just fills 5 spots with null
You need to explicitly set ArrayList() for each position before doing add() call.
Example:
sets[0] = new ArrayList<Integer>();
sets[0].add(5);
The line
sets = new ArrayList[5];
allocates the array, but does not place an ArrayList in any element of the array.
You would need
sets[0] = new ArrayList<Integer>();
sets[0].add(1);
It's because your array is initialized with null values.
//it will initialize sets variable
sets = new ArrayList[5];
//but set[0], set[1]... and on are null
You should initialize the array items as well before using them
sets[0] = new ArrayList<Integer>();
sets[0].add(1);
Also, for a better design, you should program oriented to interfaces instead of the class. See What does it mean to "program to an interface"? for more info.
In short, your code should look like
public class A {
static List<Integer> sets[];
public static void main(String[] args) {
sets = new List[5];
sets[0] = new ArrayList<Integer>();
sets[0].add(1);
//extending your code in order to use more than one value of the List array
sets[1] = new ArrayList<Integer>();
sets[1].add(20);
for(List<Integer> list : sets) {
if (list != null) {
System.out.println(list.get(0));
}
}
}
}
Related
I have declared a class named Member. I then assigned an array with Member type. When I try to put things into the array, it gives me this error:
Exception in thread "main" java.lang.NullPointerException
at HW2_2.main(HW2_2.java:15)
This is my code:
import c.Member;
import java.util.Scanner;
public class HW2_2
{
public static void main(String []args)
{
Member[] p = new Member[100];
Scanner in = new Scanner(System.in);
p[0].setID("apple12");
p[0].setPassword("1234");
p[0].setFirstname("fname");
p[0].setLastname("lname");
p[0].setEmail("*#gmail.com");
}
}
How do I fix this to the point where I can store data into my array?
You have created an object p which points to an array of Member objects. This is perfect. However, each object in your array is by default null. You cannot simply perform operations on them.
You probably want to do something like...
//...
p[0] = new Member(...);
p[0].setId("ID");
//... And so on
What's important to learn from here is that an array declaration syntax does not initialize the values of the array itself. That would be impossible, right? How would you pass arguments to the constructors of each one seperately? You have to do it manually.
When you:
Member[] p = new Member[100];
it initializes all array members to null (since this is an array of object types).
You need to initialize members if you want them to be usable, therefore here you have to:
p[0] = new Member();
before you can use that member.
If you want to initialize all members at once, you need to loop over all elements in the array and create one for each member; with Java 8 this can be done as such:
IntStream.range(0, p.length).forEach(index -> p[index] = new Member());
Curiously enough, there is no such method as <T> void fill(T[] array, Supplier<T> supplier) in the Arrays class.
I want to make an array of size 150 of the class Info
public class Info {
int Group;
String Name;
}
But I have the exception occur after
public class Mover {
static Info[] info=new Info[150];
public static void main(String[] args) {
info[0].Group=2;//I get error here
}
}
I'm not sure if there is a better way to do what a want to do, but I don't want to use a multidimensional array. I'm simply trying to add information to the group, so I'm confused.
doing new Info[150] simply instantiates an array of size 150. All elements within the array have not been instantiated and are therefore null.
So when you do info[0] it returns null and you're accessing null.Group.
You have to do info[0] = new Info() first.
This static Info[] info=new Info[150]; is creating an array of 150 objects of type info pointing to NULL.
You have to do this to get this working
for(int i = 0; i< 150; i++)
info[i] = new Info();
Then you can use these objects
Trying to get a function to fill multiple arrays with values. Would love to be able to do this:
public class Demo {
public static void getData(int[] array1, int[] array2) {
array1 = new int[5];
array2 = new int[5];
}
public static void main(String[] args) {
int[] array1 = null;
int[] array2 = null;
getData(array1, array2);
System.out.println(array1[0]); // line 11
}
}
Exception in thread "main" java.lang.NullPointerException
at Demo.main(Demo.java:11)
This gives a NullPointerException, but I'm not exactly sure why. I can't allocate the arrays in main() because there's no way to know in advance how large they'll be. Could use a List, or a 2D array, but is there a way to do this without either?
As several other commentators have mentioned, the problem here is misunderstanding the notion of pass-by-reference. Without getting into the nitty-gritty, as a rule of thumb any time you say a = ... where a is an Object (which includes arrays) you are disconnecting the name a from a previous value, and pointing it instead at your new value. There is no connection between the two, and no way to reference past values of a. So in your case, by setting array1 and array2 to new values you are no longer referencing the objects passed into the function. In this case the function arguments are null, not actual objects, but that doesn't change anything here.
The more important question however is what to do about this? Obviously the current design is unworkable, but how exactly can we do this? It's a common problem, so unsurprisingly there are many viable options.
Use static variables
The easiest thing you can do here is simply ensure both main() and getData() are working with the same variable, by using static class variables both methods can reference. While easy for simple projects, this breaks down quickly and starts introducing more problems than it solves as your project's size and scope gets bigger. Use with caution.
public class Demo {
public static void getData(int[] array1, int[] array2) {
array1 = new int[5];
array2 = new int[5];
}
public static void main(String[] args) {
int[] array1 = null;
int[] array2 = null;
getData(array1, array2);
System.out.println(array1[0]); // line 11
}
}
Use a dedicated object, and a pass around references to that object
Alternatively, we can avoid static variables by constructing a single holder object and passing around references to it. We can then freely change the instance variables inside our holder.
public class Holder {
// Should really be private, with constructors/getters/setters
// but for brevity we'll access them directly here. Don't
// take this shortcut in production code
public int[] array1;
public int[] array2;
}
public class Demo {
public static void getData(Holder holder) {
holder.array1 = new int[5];
holder.array2 = new int[5];
}
public static void main(String[] args) {
Holder holder = new Holder();
getData(holder);
System.out.println(holder.array1.length+" "+holder.array2.length);
}
}
Use a resizable data structure
You mention your concern is you don't know ahead of time the size of the loaded data, which makes this a perfect candidate for a List or other data structure. You also mention you don't want to do this, which is fine, but be really sure you actually need arrays - they provide very few benefits over proper collection types, and many more hassles. Using a resizable data structure lets us construct and populate the same object separately.
import java.util.*;
public class Demo {
public static void getData(List<Integer> ls1, List<Integer> ls2) {
// bad formatting for brevity, don't do this either
ls1.add(1); ls1.add(2); ls1.add(3); ls1.add(4); ls1.add(5);
ls2.add(1); ls2.add(2); ls2.add(3); ls2.add(4); ls2.add(5);
}
public static void main(String[] args) {
List<Integer> ls1 = new ArrayList<>();
List<Integer> ls2 = new ArrayList<>();
getData(ls1, ls2);
System.out.println(ls1.size()+" "+ls2.size());
}
}
Compartmentalize this behavior entirely into a proper object
All of the above are reasonable options given specific use cases, but they all pale in comparison to the robustness, power, and code-safety of creating a proper object and compartmentalizng the behavior entirely. What do I mean by this? Instead of having a getData() method which applies some business logic to some existing variables, group the variables and the logic together into an object - this is the core tenant of Object Oriented Programming.
public class Data {
// Again, getters/setters, but at least these are final, that's an improvement
public final int[] array1;
public final int[] array2;
public Data() {
array1 = new int[5];
array2 = new int[5];
}
}
public class Demo {
public static void main(String[] args) {
Data data = new Data();
System.out.println(data.array1.length+" "+data.array2.length);
}
}
By using a dedicated class, we hide the logic of building this data from the caller. Instead, the main() method simply constructs a Data() object, and can trust simply by constructing the object that it now has all the data it needs. No need to worry about references, array sizes, or anything else; all those decisions are dealt with correctly internally and hidden away from the caller.
Java will always pass the reference to your array declared in main so not initializing it will always get an NPE. I think you should just use List for this since you need your method to be able to define the size. Just convert to array if you need the final output to be an array.
array1 = new int[5];
array2 = new int[5];//this will create variable in function body scope
that is the reason you are getting null pointer
try:
public static void main(String[] args) {
int[] array1 = new int[5];
int[] array2 = new int[5];
getData(array1, array2);
}
public static void getData(int[] array1, int[] array2) {
// fill array1 and array2 with data
}
the way you are trying to achieve it, is not a possible way in Java
You could make an array with length 0:
public void getData(int[] array1, int[] array2) {
array1 = new int[5];
array2 = new int[5];
}
public void main(String[] args) {
int[] array1 = new int[0];
int[] array2 = new int[0];
getData(array1, array2);
}
// fill array1 and array2 with data
I am having a little trouble understanding the concept of final in Java.
I have a class that follows:
public class MyClass
{
private int[][] myArray; // intended to be changed
private final int[][] MYARRAY_ORIGINAL; // intended to be unchangable
public MyClass(int[][] array)
{
myArray = array;
MYARRAY_ORIGINAL = array;
}
}
I was under the understanding that final would make MYARRAY_ORIGINAL read only. But I have tried editing myArray, and it edits MYARRAY_ORIGINAL as well. My question is, in this context, what exactly does final do? And for extra credit, how can I copy the array passed through the constructor into MYARRAY_ORIGINAL so that I can have 2 arrays, one to edit, and one that will remain preserved?
Your final MYARRAY_ORIGINAL is indeed read only: you can't assign a new value to the MYARRAY_ORIGINAL reference in other side than class constructor or attribute declaration:
public void someMethod() {
//it won't compile
MYARRAY_ORIGINAL = new int[X][];
}
The values inside the array are not final. Those values can change anytime in the code.
public void anotherMethod() {
MYARRAY_ORIGINAL[0][0] = 25;
//later in the code...
MYARRAY_ORIGINAL[0][0] = 30; //it works!
}
If you indeed need a List of final elements, in other words, a List whose elements can't be modified, you can use Collections.unmodifiableList:
List<Integer> items = Collections.unmodifiableList(Arrays.asList(0,1,2,3));
The last piece of code was taken from here: Immutable array in Java
In case of Objects, final makes reference can't be changed, but object state can be changed.
That is the reason why you are able to change values of final MYARRAY_ORIGINAL
MYARRAY_ORIGINAL is indeed read only variable. Your array reference can not be assigned a new value nor for their length of the arrays can be changed. A final variables initialization can be deferred till the constructors is called. If one tries to modify the reference of the final variable, compiler will throw an error message. But what is possible is, one can edit the elements of the MYARRAY_ORIGINAL and of the myArray i.e one can change the state of the object assigned to a final variable. For example
Class A {
final int[] array;
public A() {
array = new int[10] // deferred initialization of a final variable
array[0] = 10;
}
public void method() {
array[0] = 3; // it is allowed
array = new int[20] // not allowed and compiler will throw an error
}
}
To understand more on final please take a look at Java Language Specification on final variable.
Final does not mean 'read-only' per se, but more so "safe publication' for other threads than the one to which it is defined. Another aim of 'final' is that it ensures the latest object available in a multi-thread environment.
Secondly, if you define something as "final", for example:
private final int[][] MYARRAY_ORIGINAL;
The reference is "final", but not the object itself. A much better way to understand it would be this:
public static final List myList = new ArrayList();
Now I can access myList from any other threads - I can modify it (add to it); but I cannot
(a) Declare it again - myList = new ArrayList();
(b) Assign it another list - myList = anotherList;
The context for final I would see best, in a multiple-thread scenario.
Bonus: to answer your question, you cannot make a 'readonly' array, you will have to manage that yourself (as final, only maintains 'read-only' to reference not object)
You can use the method System.arraycopy to make a copy of the array as follows -
int[][] source = {{1,2},{3,4}};
int[][] copy = new int[source.length][];
System.arraycopy(source, 0, copy, 0, source.length);
Also, you some problem with your code regarding what you are trying to do. If you look at the constructor
public MyClass(int[][] array) { //something else passes the array
myArray = array;
MYARRAY_ORIGINAL = array; // you are just keeping a reference to it can be modified from outside
}
If you really want nobody to modify the values in that array MYARRAY_ORIGINAL, you should make a copy of the source array that comes comes from outside.
public MyClass(int[][] array) {
myArray = array; //make a copy here also if you don't want to edit the argument array
MYARRAY_ORIGINAL = new int[array.length][];
System.arraycopy(array, 0, MYARRAY_ORIGINAL, 0, array.length);
}
Now you shouldn't have to worry about the array's being modified from outside.
I have the following function.
func(ArrayList `<String>`[] name) { ........ }
The function fills the ArrayList[]. (I don't want to return the ArrayList[])
However, in the caller function the ArrayList[] obtained has all ArrayLists as null.
For eg.
name = new ArrayList[num];
func(name);
System.out.println(name[0]);
I get NullPointerException at line 3. Is this because of line 1, i.e. I am not parametrizing? If yes, is there another way this can be done? Because java does not allow creating a generic array of parametrized ArrayList.
That is obviously not your real code, but you're creating an array of ArrayLists, which probably isn't what you want. You can probably just do:
ArrayList<String> name = new ArrayList(num);
func(name);
System.out.println(name.get(0));
Note that when you create the ArrayList, you're only specifying the initial capacity, not the size (number of initial items). It will have an initial size of 0. Your func can just call add to add items.
Even better (no typing errors):
ArrayList<String> name = new ArrayList<String>();
I recommend not bothering with the initial capacity argument (num) - just leave it blank and it will work perfectly. But do bother with the generic type of String in the constructor, or the compiler will complain.
If you want to know how to use the ArrayList (for example, why to use the get() function), you should look at the documentation.
For arrays in Java when you create it all of the elements are either 0, false, or null depending in their type.
So:
final List<String>[] foo;
foo = new ArrayList<String>[10];
foo[0].add("hello"); // crash
that crashes because foo = new ArrayList<String>[10]; allocates enough room to hold 10 ArrayList<String> but it sets all of the values to null. So you need one additional step:
for(int i = 0; i < foo.length; i++)
{
foo[i] = new ArrayList<String>();
}
I haven't compiled the code, but pretty sure it is all correct. You would do that between step 1 and 2 of your program.
I am guessing a bit because your code isn't quite accurate (it would not generate a null pointer as written as near as I can tell).
EDIT:
You would do the new in the method and the for loop with the assignments could be done inside of the method. I prefer to allocate and initialize in the same place (less confusing) but you can split it up if you needed to.
The problem you are encountering is due to the fact that in Java, parameters to methods are passed by value. What this means, is that every parameter is effectively "copied" into the method, meaning that any assignments you make to the parameters are only visible within the method, and cannot be seen by the caller.
Going by your example, you're passing in a null reference to an array of List<String>'s. This reference is then "copied" into the func() method, and when func then assigns something to this variable, it is only the local variable that is being updated, and not the reference held by your calling code.
Here's some compilable code (based on your example) that demonstrates the problem:
public class Main {
public static void main(String[] args) {
List<String>[] array = null;
fill(array);
System.out.println("In main(): " + array[0].get(0));
}
public static void fill(List<String>[] array) {
array = (List<String>[])new List[10];
array[0] = new ArrayList<String>();
array[0].add("test");
System.out.println("In fill(): " + array[0].get(0));
}
}
The println in fill prints the correct value, because the array variable has been assigned to something within the fill method, however the println in the main method throws an NPE because only the "copy" of the array variable was changed by func, and not the "real" variable.
There are two ways to get around this: either instantiate the array within your calling code, or change the fill() method to return a reference to the array is has created.
Below is the first approach:
public class Main {
public static void main(String[] args) {
List<String>[] array = (List<String>[])new List[10];
fill(array);
System.out.println("In main(): " + array[0].get(0));
}
public static void fill(List<String>[] array) {
array[0] = new ArrayList<String>();
array[0].add("test");
System.out.println("In fill(): " + array[0].get(0));
}
}
You may be wondering why this works, because you're still assigning ArrayList's to the elements of the array, however these objects are visible outside of the calling method. The reason for this is that although the fill method is getting a "copy" of the reference to the array, the reference itself is still referencing the same array object. This means that you can modify the internal state of the array object, and any changes you make will be seen by the caller because it referencing that same object.
Below is the second approach:
public class Main {
public static void main(String[] args) {
List<String>[] array = fill();
System.out.println("In main(): " + array[0].get(0));
}
public static List<String>[] fill() {
List<String>[] array = (List<String>[])new List[10];
array[0] = new ArrayList<String>();
array[0].add("test");
System.out.println("In fill(): " + array[0].get(0));
return array;
}
}
(As an aside, you should generally try to avoid creating arrays of generic collections, a better idea would be to use a list to store the lists themselves. E.g:
List<List<String>> list = new ArrayList<List<String>>();
list.add(new ArrayList<String>());
list.get(0).add("test");
new ArrayList<?>[10] give me incompatible type. However, new ArrayList[10] works for me.