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
Related
Just trying to understand the basics of how this should work. Here is my code.---------------------------> This is my main class.
public class Driver
{
public static void main(String[] args)
{
//create new instance of the ArrayLab class with parameter of 10
ArrayLab array = new ArrayLab(10);
//search for 2
array.search(2);
}
}
The class ArrayLab has a method assigned to it called search with parameter of (2). So far this is what I have.
import java.util.Arrays;
public class ArrayLab
{
//array instance variable
int[] array1 = new int[10];
//array constructor
public ArrayLab(int integer)
{
//class parameter = 10
int[] array1 = new int[integer];
}
//method
public void search(int integer)
{
int[] array1= new int[]{integer};
System.out.println(Arrays.toString(array1));
}
}
So the big question is what am I doing right? or wrong? I realize this is probably pretty basic, just struggling to understand what is happening inside the code. Thanks :)
Your Driver class is good.
So, lets take one line at a time
int[] array1 = new int[10];
Okay, you made a public int array of size 10, more precisely [0, 0, 0, 0, 0, 0, 0, 0, 0, 0].
public ArrayLab(int integer)
{
int[] array1 = new int[integer];
}
This is called a constructor. You are passing in integer, and making a new array called array1 which is local to this scope, therefore different than the one before. This array1 contains integer-many zeros.
To use and initialize the previous array1, change your code up to here to this
int[] array1;
public ArrayLab(int integer)
{
this.array1 = new int[integer];
}
Next,
public void search(int integer)
{
int[] array1= new int[]{integer};
}
}
This, again, creates a new array, but only one value. So say integer was 2, then [2].
I don't know what the purpose of your ArrayLab class is , but here are some problems
In the constructor you are initializing a local array1 not your instance variable .
search method is doing nothing but again initializing a local array1.
Alright, so whats happening is in your class Driver your creating a object of your class ArrayLab. You send this class a constructor which creates a local variable array1. Your search class initializing another local array1 this is what i would do for your ArrayLab class
import java.util.Arrays;
public class ArrayLab
{
int[] array1;
//array constructor
public ArrayLab(int integer)
{
this.array1 = new int[integer];
}
//method
public void search(int integer)
{
System.out.println(array1[integer]);
}
}
I am aware that the idea of the keyword private is to enable encapsulation. However, I got confused when I realized that I can modify an Array after retrieving it with a getter, which surprised me. The same didn't work for the plain integer, although I thought java treats all variables as objects.
The example:
public class PrivContainer {
private int[] myIntArray;
private int myInt;
PrivContainer(){
myIntArray=new int[1];
myIntArray[0]=3;
myInt=22;
}
public int[] getIntArray(){
return myIntArray;
}
public int getInt(){
return myInt;
}
public void printInt(){
System.out.println(myIntArray[0]);
System.out.println(myInt);
}
}
public class Main {
public static void main(String[] args){
PrivContainer pc=new PrivContainer();
int[] r=pc.getIntArray();
int q=pc.getInt();
r[0]=5;
q=33;
pc.printInt();
}
}
The Output of printInt() is 5,22
This means that main method could change the entries of the private array but not of the private int.
Could someone explain this phenomena to me?
An array is a mutable Object. Therefore, if you have a reference to that array, you can modify its contents. You can't do the same with primitive members of a class (such as int) and with references to immutable class instances (such as String and Integer).
Your assignment :
q=33;
Would be similar to :
r = new int [5];
Both of those assignments cause the variables to contain new values, but they don't affect the state of the PrivContainer instance from which the original values of those variables were assigned.
Nothing seems strange here. What happen basically as follow.
public class Main {
public static void main(String[] args){
PrivContainer pc=new PrivContainer(); <-- create new `PrivContiner` object which also initialised the private variables
int[] r=pc.getIntArray(); <-- you get the "object" integer array here and assign r to refer to that object
int q=pc.getInt(); <-- you get the "primitive" integer here and assign q to refer the myInt variable here.
r[0]=5; <-- you assign the first value of the array 5. Note that the object reference is still the same here
q=33; <-- you assign the variable q to 33. Note that, this mean, the variable q refer to another primitive here (which is 33)
pc.printInt(); <-- print the content of the object here.
}
}
When you invoke the printInt function. the output will be 5 and 22 as the new integer (33) is assigned to q and its scope is only within the main function.
While you return an array from a getter you return the reference of that object. Since you have the reference you can change its elements. If you want to avoid this behavior you will have to return the clone of your array in that case you wont be able to change the elements of your array
public class Main {
public static void main(String... args) {
Arr arr = new Arr();
int[] y = arr.getX();
y[1] = 5;
System.out.println(arr.getX()[1]);
}
}
class Arr {
private int[] x = {1, 2, 3};
public int[] getX() {
return x.clone();
}
}
Try this code and remove the clone method, like this
class Arr {
private int[] x = {1, 2, 3};
public int[] getX() {
return x;
}
}
Now execute the main method, you will observe that changing value of y will change the value of array x as well.
I tried to make a parameter for an array for a method, but it always comes up with an error.
public void methodExample1() {
int array1[] = new int[4]
}
public void methodExample(Array array1[]) {
System.out.println(array1[0]);
}
But it always says there's an error in my parameter. Is there any way to do this?
Try this:
public void methodExample(int[] array1)
Explanation: The type is the same that you used for declaring a value that will be passed as parameter (for the moment I'm ignoring covariant arrays), for instance if you do this:
int[] array1 = new int[4];
... Then, at the time of passing it as a parameter we'll write it like this:
methodExample(array1)
Also notice that the size of the array must not be passed as parameter, and that by convention the [] part goes right after the type of the array's elements (in fact, int[] is the type of the array), and not after the array's name.
If I understand your question, then you could use Array, and something like
public static void methodExample(Object array1) {
int len = Array.getLength(array1);
for (int i = 0; i < len; i++) {
System.out.printf("array1[%d] = %d%n", i, Array.get(array1, i));
}
}
public static void main(String[] args) {
methodExample(new int[] { 1, 2, 3 });
}
Output is
array1[0] = 1
array1[1] = 2
array1[2] = 3
I assume that you are trying to pass array as a parameter to a method , to initialize it and then call another method to print it?
In java you have to create an object and "allocate" memory space for it by calling to new ...
so you can do like that :
public static void main(String[] args) {
int [] m_array; // creating a array reference
m_array = new int[5]; // allocate "memory" for each of of them or you can consider it as creating a primitive of int in each cell of the array
method(m_array); // passing by value to the method a reference for the array inside the method
}
public void method(int [] arr) // here you are passing a reference by value for the allocated array
{
System.out.println(arr[0]);
}
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.
Hi all I have an immutable array implementation which looks like this:
public static final class FixedArray<T> {
private final T[] array;
public final int Length;
#SafeVarargs
public FixedArray(T... args) {
array = args;
Length = args.length;
}
public T Get(int index) {
return array[index];
}
}
public static final class FixedIntArray {
private final int[] array;
public final int Length;
public FixedIntArray(int... args) {
array = args;
Length = args.length;
}
public int Get(int index) {
return array[index];
}
}
public static final class FixedLongArray {
private final long[] array;
public final int Length;
public FixedLongArray(long... args) {
array = args;
Length = args.length;
}
public long Get(int index) {
return array[index];
}
}
Initially I'd thought that it is guaranteed to be thread-safe. But after reading the discussion regarding immutable arrays and the Java Memory Model, I believe alone, I can't be sure.
I've not used a defensive copy, with the contract that the calling code "does the right thing" (and as usual, if it doesn't follow the contract, the behavior is undefined).
The calling method looks like this:
public static void main(String args[]) {
int[] ints = new int[10000];
FixedIntArray fixed_ints = new FixedIntArray(ints);
SendToThreadA(fixed_ints);
SendToThreadB(fixed_ints);
SendToThreadC(fixed_ints);
SendToThreadD(fixed_ints);
//caller (which is this method) does the right thing, ints goes out of scope without anyone trying to modify it.
}
I was wondering is the code above guaranteed to be thread-safe?
As we don't know what happens to the array (and its values) to which you store a reference, I think your classes would be much safer if the constuctors create a copy of the argument array and set the internal final reference to the copied array.
It's OK. You can require caller to "hand-off" the array to you. Caller can clone one if necessary.
Memory write is usually the most expensive thing in a program (sans external IO).
Not everybody is stupid. You only need to be defensive enough to protect your target user base.
Given that you can pass an array to a varargs method, you'd need to make a copy of the constructor input to ensure it can't be modified outside the class. Having done that, as long as you don't assign the final field until after all the values are assigned in the copy array, you should be fine because the assignment to the final field is guaranteed to happen before any read of that field from another thread.
So a constructor would look like:
array = Arrays.copyOf(args, args.length);
Orrrr you could just use a Guava ImmutableList and get a lot more power.
I'm not sure it's meaningful to examine it for thread-safety, because it's missing even a more basic level of safety. Consider this method:
public static void main(final String... args)
{
final int[] arr = new int[] { 3, 3, 3 };
final FixedIntArray threeThrees = new FixedIntArray(arr);
System.out.println(threeThrees.Get(0)); // prints "3"
System.out.println(threeThrees.Get(1)); // prints "3"
System.out.println(threeThrees.Get(2)); // prints "3"
arr[0] = arr[1] = arr[2] = 4;
System.out.println(threeThrees.Get(0)); // prints "4"
System.out.println(threeThrees.Get(1)); // prints "4"
System.out.println(threeThrees.Get(2)); // prints "4"
}
The problem is that, when a method that takes int... (or Object... or long... or anything else), it can receive either an array that's implicitly constructed by the compiler (as would happen if you typed new FixedIntArray(3,3,3)), or an array that's explicitly passed in by the calling code (as I did above). In the latter case, the calling code can continue to modify the array that it passed in!