You have created the array already, and your setArraySize changes the size variable only.
public class SortTests {
private static int size; <-- setArraySize affects this.
private static int [] myArray = new int [size]; <-- setArraySize does not affect this. Size was defaulted to 0, so myArray will always be a 0-sized array.
Change to something similar to this:
public class SortTests {
private static int [] myArray = new int [size];
public static void setArraySize() {
Scanner scan = new Scanner(System.in);
System.out.println("Enter a whole number to specify the size of the array: ");
int size = scan.nextInt();
myArray = Arrays.copyOf(myArray, size);
}
Answer from John on Stack OverflowYou have created the array already, and your setArraySize changes the size variable only.
public class SortTests {
private static int size; <-- setArraySize affects this.
private static int [] myArray = new int [size]; <-- setArraySize does not affect this. Size was defaulted to 0, so myArray will always be a 0-sized array.
Change to something similar to this:
public class SortTests {
private static int [] myArray = new int [size];
public static void setArraySize() {
Scanner scan = new Scanner(System.in);
System.out.println("Enter a whole number to specify the size of the array: ");
int size = scan.nextInt();
myArray = Arrays.copyOf(myArray, size);
}
To add to @John's answer
This is not the correct way to initialize Arrays. You're using the compiler-provided default value for for an int (which is 0) to initialize the length of myArray. The initialization of myArray occurs on class instantiation. This means that size is read once when the class is created, then discarded. Thus, the initial array size from the code you provided will always be the length of the original value of size. Since size was 0, it is proper for the array to be empty.
If you want to retrieve an array of a specific size, you need to create it dynamically after the user has submitted his input (Per @John's answer)
Additionally, you will definitely want to consider using Java's Collections framework instead of dealing with raw Arrays. Array sizes are managed dynamically.
package com.company;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;
public class ScannerToArraySize {
private static Integer size;
private static ArrayList<Integer> myArray = new ArrayList<>();
public static void setArraySize() {
Scanner scan = new Scanner(System.in);
System.out.println("Enter a whole number to specify the size of the array: ");
size = scan.nextInt();
}
public static void fillArray() {
Random randNum = new Random();
for (int i = 0; i < size; i++) {
myArray.add(randNum.nextInt(100));
}
}
public static void printArray(){
for (Integer integer : myArray) {
System.out.println(integer);
}
}
}
You can either use array declaration or array literal (but only when you declare and affect the variable right away, array literals cannot be used for re-assigning an array).
For primitive types:
int[] myIntArray = new int[3]; // each element of the array is initialised to 0
int[] myIntArray = {1, 2, 3};
int[] myIntArray = new int[]{1, 2, 3};
// Since Java 8. Doc of IntStream: https://docs.oracle.com/javase/8/docs/api/java/util/stream/IntStream.html
int [] myIntArray = IntStream.range(0, 100).toArray(); // From 0 to 99
int [] myIntArray = IntStream.rangeClosed(0, 100).toArray(); // From 0 to 100
int [] myIntArray = IntStream.of(12,25,36,85,28,96,47).toArray(); // The order is preserved.
int [] myIntArray = IntStream.of(12,25,36,85,28,96,47).sorted().toArray(); // Sort
For classes, for example String, it's the same:
String[] myStringArray = new String[3]; // each element is initialised to null
String[] myStringArray = {"a", "b", "c"};
String[] myStringArray = new String[]{"a", "b", "c"};
The third way of initializing is useful when you declare an array first and then initialize it, pass an array as a function argument, or return an array. The explicit type is required.
String[] myStringArray;
myStringArray = new String[]{"a", "b", "c"};
There are two types of array.
One Dimensional Array
Syntax for default values:
int[] num = new int[5];
Or (less preferred)
int num[] = new int[5];
Syntax with values given (variable/field initialization):
int[] num = {1,2,3,4,5};
Or (less preferred)
int num[] = {1, 2, 3, 4, 5};
Note: For convenience int[] num is preferable because it clearly tells that you are talking here about array. Otherwise no difference. Not at all.
Multidimensional array
Declaration
int[][] num = new int[5][2];
Or
int num[][] = new int[5][2];
Or
int[] num[] = new int[5][2];
Initialization
num[0][0]=1;
num[0][1]=2;
num[1][0]=1;
num[1][1]=2;
num[2][0]=1;
num[2][1]=2;
num[3][0]=1;
num[3][1]=2;
num[4][0]=1;
num[4][1]=2;
Or
int[][] num={ {1,2}, {1,2}, {1,2}, {1,2}, {1,2} };
Ragged Array (or Non-rectangular Array)
int[][] num = new int[5][];
num[0] = new int[1];
num[1] = new int[5];
num[2] = new int[2];
num[3] = new int[3];
So here we are defining columns explicitly.
Another Way:
int[][] num={ {1}, {1,2}, {1,2,3,4,5}, {1,2}, {1,2,3} };
For Accessing:
for (int i=0; i<(num.length); i++ ) {
for (int j=0;j<num[i].length;j++)
System.out.println(num[i][j]);
}
Alternatively:
for (int[] a : num) {
for (int i : a) {
System.out.println(i);
}
}
Ragged arrays are multidimensional arrays.
For explanation see multidimensional array detail at the official java tutorials
Videos
You cannot do it like that. In Java, the type of an array does not include it's size. See my answer to this earlier question. (Ignore the part about abstract methods in that question ... it's not the real issue.)
The size of an array is determined by the expression that creates it; e.g. the following creates a char array that contains 5 characters, then later replaces it with another array that contains 21 characters.
public char[] language = new char[5];
...
language = new char[21];
Note that the creation is done by the expression on the RHS of the equals. The length of an array is part of its 'value', not its 'type'.
To quote the JLS :
An array's length is not part of its type.
To initialize an array you should do :
public char[] language = new char[5];
Other solutions are
public char[] language = {0, 0, 0, 0, 0};
or
public char[] language;
language = new char[5];
In Java, the array declaration can't contain the size of the array; we only know the variable will contain an array of a specific type. To have an array initialized (and with a size) you have to initialize it either by using new or by using a shortcut which allows to initialize and set values for an array at the same time.
Best way to have to check if an array has a specified size, is actually checking the size of the array yourself with something like if(array.length == 5).
Resources :
- JLS - Array Types
- JLS - Array Creation Expressions
On the same topic :
- abstract method of a set length array in java?
You're confusing the size of the array list with its capacity:
- the size is the number of elements in the list;
- the capacity is how many elements the list can potentially accommodate without reallocating its internal structures.
When you call new ArrayList<Integer>(10), you are setting the list's initial capacity, not its size. In other words, when constructed in this manner, the array list starts its life empty.
One way to add ten elements to the array list is by using a loop:
for (int i = 0; i < 10; i++) {
arr.add(0);
}
Having done this, you can now modify elements at indices 0..9.
If you want a list with a predefined size you can also use:
List<Integer> arr = Arrays.asList(new Integer[10]);
I used the Arrays.copyOf method, like this:
int myArray[] = {1,2,3};
myArray = Arrays.copyOf(myArray, myArray.length+1);
//previous line creates a copy of the array and adds one to the size
myArray[3] = 12; // assign the new fourth element the value of 12
//then loop through the array to output each element
for(int ctr = 0; ctr<myArray.length; ctr++){
System.out.println(myArray[ctr]);
}
Yes, your array variable may reference an array of the same type but different size.
For changing it internally, an ArrayList might be more easy to use.
Abridged:
For an array: use .length.
For a Collection (or Map): use .size().
For a CharSequence (which includes CharBuffer, Segment, String, StringBuffer, and StringBuilder): use .length().
Arrays
One would use the .length property on an array to access it. Despite an array being a dynamically created Object, the mandate for the length property is defined by the Java Language Specification, ยง10.3:
An array is created by an array creation expression (ยง15.10) or an array initializer (ยง10.6).
An array creation expression specifies the element type, the number of levels of nested arrays, and the length of the array for at least one of the levels of nesting. The array's length is available as a final instance variable
length.An array initializer creates an array and provides initial values for all its components.
Since the length of an array cannot change without the creation of a new array instance, repeated accesses of .length will not change the value, regardless of what is done to the array instance (unless its reference is replaced with a differently sized array).
As an example, to get the length of a declared one-dimensional array, one would write this:
double[] testScores = new double[] {100.0, 97.3, 88.3, 79.9};
System.out.println(testScores.length); // prints 4
To get lengths in an n-dimensional array, one needs to bear in mind that they are accessing one dimension of the array at a time.
Here's an example for a two-dimensional array.
int[][] matrix
= new int[][] {
{1, 2, 3, 4},
{-1, 2, -3, 4},
{1, -2, 3, -4}
};
System.out.println(matrix.length); // prints 3 (row length or the length of the array that holds the other arrays)
System.out.println(matrix[0].length); // prints 4 (column length or the length of the array at the index 0)
This is important to make use of, especially in the case of jagged arrays; the columns or rows may not always line up all the time.
Collections (Set, List, etc.)
For every object that implements the Collection interface, they will have a method called size() with which to access the overall size of the collection.
Unlike arrays, collections are not fixed length, and can have elements added or removed at any time. A call to size() will produce a nonzero result if and only if there has been anything added to the list itself.
Example:
List<String> shoppingList = new ArrayList<>();
shoppingList.add("Eggs");
System.out.println(shoppingList.size()); // prints 1
Certain collections may refuse to add an element, either because it's null, or it's a duplicate (in the case of a Set). In this case, repeated additions to the collection will not cause the size to increment.
Example:
Set<String> uniqueShoppingList = new HashSet<>();
uniqueShoppingList.add("Milk");
System.out.println(uniqueShoppingList.size()); // prints 1
uniqueShoppingList.add("Milk");
System.out.println(uniqueShoppingList.size()); // prints 1
Accessing the size of a List<List<Object>>* is done in a similar way to a jagged array:
List<List<Integer>> oddCollection = new ArrayList<>();
List<Integer> numbers = new ArrayList<Integer>() {{
add(1);
add(2);
add(3);
}};
oddCollection.add(numbers);
System.out.println(oddCollection.size()); // prints 1
System.out.println(oddCollection.get(0).size()); // prints 3
*: Collection doesn't have the get method defined in its interface.
As an aside, a Map is not a Collection, but it also has a size() method defined. This simply returns the number of key-value pairs contained in the Map.
String
A String has a method length() defined. What it does is print the number of characters present in that instance of the String.
Example:
System.out.println("alphabet".length()); // prints 8
Don't forget CollectionUtils.size() from the commons library, its null safe so you don't have to null check beforehand.
Sure, just declare it where you have it with public int[] myIntArray; and then initialize it as soon as you know how big it has to be with myIntArray = new int[x];
You could declare it but not instantiate with public int[] myIntArray;
Later, after your code x = input.nextInt();, instantiate the array with myIntArray = new int[x] within that method. You should still be able to access the array from other methods
1
You should declare the fields elements and top as private. Also, since you do not expand the storage array (elements), you can declare it final as well.
2
It's kind of funny that your stack grows from larger indices towards smaller ones. I suggest you rename top to size, and make your stack grow towards larger indices. That way, the value of size will be the storage array index at which the next pushed element would be placed.
3
In the constructor, you call erase that sets all the storage array components to null. Don't do this, JVM initializes all object array components to null by default.
Suppressing warnings
It's recommended to suppress the smallest possible unit. For example here:
@SuppressWarnings("unchecked") public void setSize(int size){ this.elements = (E[]) new Object[size]; resetTop(false); }
Instead of suppressing the unchecked warning in the entire method, it would be better to do it for the one offending statement, like this:
public void setSize(int size){
@SuppressWarnings("unchecked")
this.elements = (E[]) new Object[size];
resetTop(false);
}
In some methods you suppress unnecessarily, for example here:
@SuppressWarnings("unchecked") public FixedStack(int capacity) { setSize(capacity); resetTop(false); }
I'm going to take a wild guess that in a previous version there was indeed an offending statement in this method. You suppressed the warning at the method level, then refactored the code, the offending statement got moved somewhere else, and you forgot to remove the suppression. This mistake would not have happened if you had suppressed at the statement level, you see?
Encapsulation
I'm wondering if you really intended for some of the methods to be public. For example setSize and resetTop. These methods manipulate the internal state of the stack, which is not common in stack implementations. I think these should be private, to hide from users.
On a related note, it would be better to extract the interface of the fixed stack, which would make it perfectly clear whih methods are intentionally exposed.
Avoid confusion by better names
I purposely throw a custom
StackOverflowExceptionsubclassingjava.lang.IndexOutOfBoundsExceptionrather than ajava.lang.StackOverflowErroras the latter indicates an overflow of the JVM internal stack specifically.
To avoid confusion, I propose the name FixedStackOverflowException for your custom exception class.
As mentioned in @rolfl's to your later question, there is limited value in this class as elements cannot be easily retrieved.
Putting aside the obvious improvements to the seemingly toy implementations, you have a mistake in describing whether the stack has 'overflow' or 'underflow': the meanings should be inversed. When you try to push(int) to a full stack, that is known as an overflow, and you need to check whether the stack is empty when pop()-ping instead of checking for 'overflows'.
To better indicate error conditions such as those mentioned above, you can make use of throwing Exceptions instead of a simple System.out.println(). In fact, I will suggest using System.err.println() at the very least to differentiate between normal and error 'outputs'.
A Java 8 way of printing the contents of the stack is to use Arrays.stream(int[]):
public void display() {
Arrays.stream(stack).forEach(System.out::println);
}
This uses System.out.println(int) as a method reference to print each int value on the console.
Simply running through some test operations in the main() method is also barely enough, you should consider proper unit testing techniques such as using a testing framework that can arrange-act-assert for you.
Last but not least, you should also take a look at the standard JDK classes' stack implementations for greater inspiration, such as the Deque interface.
Why not just throw exceptions instead of writing something to the console? Also make use of generics? It is highly unlikely that Stack will be used only for integers. A stack implementation using arrays is good, but most of the time people also use LinkedList to implement it, so that you do not have to resize once you exceed INITIAL_CAPACITY. It all comes down to the user's choice.
Here are two implementations which can be useful:
Array implementation of Java Stack
My own Stack Implementation in Java
You can't resize an array in Java. You'd need to either:
Create a new array of the desired size, and copy the contents from the original array to the new array, using
java.lang.System.arraycopy(...);Use the
java.util.ArrayList<T>class, which does this for you when you need to make the array bigger. It nicely encapsulates what you describe in your question.Use
java.util.Arrays.copyOf(...)methods which returns a bigger array, with the contents of the original array.
Not nice, but works:
int[] a = {1, 2, 3};
// make a one bigger
a = Arrays.copyOf(a, a.length + 1);
for (int i : a)
System.out.println(i);
as stated before, go with ArrayList
Instead of using an array, use an implementation of java.util.List such as ArrayList. An ArrayList has an array backend which holds values in a list, but the array size is automatically handles by the list.
ArrayList<String> list = new ArrayList<String>();
list.add("some string");
You can also convert the list into an array using list.toArray(new String[list.size()]) and so forth for other element types.
On a low level you can do it this way:
long[] source = new long[1];
long[] copy = new long[source.length + 1];
System.arraycopy(source, 0, copy, 0, source.length);
source = copy;
Arrays.copyOf() is doing same thing.
No you can't change the size of an array once created. You either have to allocate it bigger than you think you'll need or accept the overhead of having to reallocate it needs to grow in size. When it does you'll have to allocate a new one and copy the data from the old to the new:
int[] oldItems = new int[10];
for (int i = 0; i < 10; i++) {
oldItems[i] = i + 10;
}
int[] newItems = new int[20];
System.arraycopy(oldItems, 0, newItems, 0, 10);
oldItems = newItems;
If you find yourself in this situation, I'd highly recommend using the Java Collections instead. In particular ArrayList essentially wraps an array and takes care of the logic for growing the array as required:
List<XClass> myclass = new ArrayList<XClass>();
myclass.add(new XClass());
myclass.add(new XClass());
Generally an ArrayList is a preferable solution to an array anyway for several reasons. For one thing, arrays are mutable. If you have a class that does this:
class Myclass {
private int[] items;
public int[] getItems() {
return items;
}
}
you've created a problem as a caller can change your private data member, which leads to all sorts of defensive copying. Compare this to the List version:
class Myclass {
private List<Integer> items;
public List<Integer> getItems() {
return Collections.unmodifiableList(items);
}
}
In java array length is fixed.
You can use a List to hold the values and invoke the toArray method if needed
See the following sample:
import java.util.List;
import java.util.ArrayList;
import java.util.Random;
public class A {
public static void main( String [] args ) {
// dynamically hold the instances
List<xClass> list = new ArrayList<xClass>();
// fill it with a random number between 0 and 100
int elements = new Random().nextInt(100);
for( int i = 0 ; i < elements ; i++ ) {
list.add( new xClass() );
}
// convert it to array
xClass [] array = list.toArray( new xClass[ list.size() ] );
System.out.println( "size of array = " + array.length );
}
}
class xClass {}
Using
OpenJDK 64-Bit Server VM (build 15.0.2+7, mixed mode, sharing)
... on MacOS, the answer seems to be Integer.MAX_VALUE - 2. Once you go beyond that:
cat > Foo.java << "END"
public class Foo {
public static void main(String[] args) {
boolean[] array = new boolean[Integer.MAX_VALUE - 1]; // too big
}
}
END
java -Xmx4g Foo.java
... you get:
Exception in thread "main" java.lang.OutOfMemoryError:
Requested array size exceeds VM limit
This is (of course) totally VM-dependent.
Browsing through the source code of OpenJDK 7 and 8 java.util.ArrayList, .Hashtable, .AbstractCollection, .PriorityQueue, and .Vector, you can see this claim being repeated:
/** * Some VMs reserve some header words in an array. * Attempts to allocate larger arrays may result in * OutOfMemoryError: Requested array size exceeds VM limit */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
which is added by Martin Buchholz (Google) on 2010-05-09; reviewed by Chris Hegarty (Oracle).
So, probably we can say that the maximum "safe" number would be 2 147 483 639 (Integer.MAX_VALUE - 8) and "attempts to allocate larger arrays may result in OutOfMemoryError".
(Yes, Buchholz's standalone claim does not include backing evidence, so this is a calculated appeal to authority. Even within OpenJDK itself, we can see code like return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; which shows that MAX_ARRAY_SIZE does not yet have a real use.)