As a practice exercise, I am creating my own generic class that is basically a copy of ArrayList. While testing the class with JUnit, I come across a NullPointerException error in the add method:
public void add(int index, T element) {
if (index > this.size() || index < 0) {
throw new IndexOutOfBoundsException();
}
if (this.size() == data.length) {
// ^ This is the line that the error points to
resize(this.data);
}
for (int i = index; i < this.size; i++) {
this.data[i + 1] = this.data[i]; //fix
}
this.data[index] = element;
size++;
}
After messing around with the class a lot, I can't figure out where the error is coming from. I can provide any details/other parts of the class that are needed. Any guidance as to where the problem is located would be fantastic. Thank You.
The constructor for the class:
MyArrayList(int startSize) {
// round the startSize to nearest power of 2
int pow2 = 1;
do {
pow2 *= 2;
} while (pow2 < startSize);
startSize = pow2;
this.size = 0;
T[] data = (T[]) new Object[startSize];
}
The following test case tests the size, but encounters the error when it tries to add an element:
public void testSize() {
MyArrayList<Integer> test = new MyArrayList<Integer>();
ArrayList<Integer> real = new ArrayList<Integer>();
assertEquals("Size after construction", real.size(), test.size());
test.add(0,5);
real.add(0,5);
assertEquals("Size after add", real.size(), test.size());
}
T[] data = (T[]) new Object[startSize];
That initializes the local variable data. Which you don't want.
Change it to following to make sure that you initialize the instance variable -
this.data = (T[]) new Object[startSize];
I the NPE is on the line you have mentioned it is only because data is null. Where are you initialyzing data ?
Maybe when you are creating your CustomArrayList you are not initialyzing your internal array data.
The data intialisation is the problem. It should be this.data = (T[])new Object[startSize];
Related
I was able to make the Constructor and capacity methods to works but don;t know why size(),isFull() and isEmpty() fails.I believe its pretty simple but i am just unable to see a minor error and fix it.Hope someone can clarify what i am doing wrong with thorough explaination.Also,my constructor works with the test file and it passes,but just want to know Is my constructor correct as specified by question?
import java.util.Arrays;
import java.util.Iterator;
public class SortedArray<T extends Comparable> implements
java.lang.Iterable<T> {
public SortedArray(int capacity) {
this.array = (T[]) new Comparable[0];
this.capacity = capacity;
this.size = 0;
}
public SortedArray(int capacity, T[] data) {
if(capacity > data.length)
{
this.capacity = capacity;
}
else {
this.capacity = data.length;
}
this.size = data.length;
this.array = (T[]) new Comparable[0];
}
final public int size() {
return this.size
}
final public int capacity() {
return this.capacity;
}
final boolean isEmpty() {
return size == 0;
}
final boolean isFull(){
return size == capacity;
}
#Override
final public Iterator<T> iterator() {
// Do not modify this method.
return Arrays.stream(array).iterator();
}
// Do not modify these data members.
final private T[] array; // Storage for the array's element
private int size; // Current size of the array
final private int capacity; // Maximum size of the array
}
//// Test File:
#Test
public void testConstructor() {
System.out.println("Constructors");
SortedArray array = new SortedArray(20);
assertEquals(array.size(), 0);
assertEquals(array.capacity(), 20);
Integer[] data = {1, 2, 3, 4};
array = new SortedArray(20, data);
assertEquals(array.size(), 4);
assertEquals(array.capacity(), 20);
array = new SortedArray(2, data);
assertEquals(array.size(), 4);
assertEquals(array.capacity(), 4);
}
#Test
public void testSize() {
System.out.println("size");
SortedArray arr = new SortedArray(10);
// Array is initially empty
assertEquals(arr.size(), 0);
// Inserting elements increases size
arr.add(12);
arr.add(13);
arr.add(14);
assertEquals(arr.size(), 3);
// Inserting duplicates increases size
arr.add(12);
arr.add(13);
assertEquals(arr.size(),5);
// Fill up the array
for(int i = 0; i < 5; ++i)
arr.add(i);
assertEquals(arr.size(), 10);
// Size does not change when array is full
arr.add(10);
arr.add(11);
assertEquals(arr.size(), 10);
// Removing elements decreases size
arr.remove(0);
arr.remove(1);
arr.remove(2);
assertEquals(arr.size(), 7);
// but removing elements that don't exist doesn't change anything
arr.remove(100);
assertEquals(arr.size(), 7);
// Removing from the empty array doesn't change size.
SortedArray empty = new SortedArray(10);
empty.remove(10);
assertEquals(empty.size(), 0);
}
#Test
public void testCapacity() {
System.out.println("capacity");
SortedArray array = new SortedArray(20);
assertEquals(array.capacity(), 20);
array = new SortedArray(100);
assertEquals(array.capacity(), 100);
Integer[] data = {1,2,3,4,5,6,7,8,9,0};
array = new SortedArray(20, data);
assertEquals(array.capacity(), 20);
array= new SortedArray(5, data);
assertEquals(array.capacity(), 10);
}
#Test
public void testIsEmpty() {
System.out.println("isEmpty");
SortedArray array = new SortedArray(10);
assertTrue(array.isEmpty());
array.add(10);
assertFalse(array.isEmpty());
array.remove(10);
assertTrue(array.isEmpty());
}
#Test
public void testIsFull() {
System.out.println("isFull");
SortedArray array = new SortedArray(5);
assertFalse(array.isFull());
array.add(10);
array.add(11);
array.add(12);
array.add(13);
array.add(14);
assertTrue(array.isFull());
array.remove(10);
assertFalse(array.isFull());
}
#Test
public void testIterator() {
}
testSize Failed : Expected <0> but was <3>
testCapacity Failed : Expected <5> but was <10>
testConstructor Failed : Expected <0> but was <4>
testisFull Failed : jUnit.framework.AssertionFailedError
testisEmpty Failed : jUnit.framework.AssertionFailedError
You forgot to include your "add(T toAdd)" and "remove(T toRemove)" methods, which when I was going through to make the tests pass, was the source of a vast majority of the fails. (Note: a trace of the fails would help, since your adds and removes need to be pretty complicated to fit the design it seems you intend)
Anyways, on to fixing what I can see.
In your second constructor, you never actually assign the data you take in. You call this.array = (T[]) new Comparable[0]; which creates an empty array of type Comparable. In reality, you need to call this.array = data in order to keep what's been given to you.
Another thing, in your size() method you forgot to place a semicolon after this.size. That tends to prevent things from passing.
Finally, final private T[] array can't have final, or you'll never be able to add or remove elements.
As a bonus, here are the add() and remove() methods I used to fit the requirements and make the tests pass (with comments!!!!):
public void add(T t) {
if (!(size >= capacity)) { //If there's room...
if (size == 0) //If the array is empty...
array[0] = t; //Add to first index
else
array[size] = t; //Add to next available index
size++;
}
}
public void remove(T element) {
if (size <= 0) //If the array is empty...
return; //Stop here
else {
for (int i = 0; i <= this.size(); i++) { //Linear search front-to-back
if (array[i].equals(element)) { //Find first match
array[i] = null; //Delete it
size--;
if (i != size) { //If the match was not at the end of the array...
for (int j = i; j <= (this.size() - 1); j++)
array[j] = array[j + 1]; //Move everything after the match to the left
}
return; //Stop here
}
}
}
}
On a side note, your calls to create SortedArray objects should really be parameterized (Using the <> such as SortedArray<Integer> arr = new SortedArray<Integer>(5, data);).
public class MyArrayList<T> implements MyList<T>{
int num; //number of things in the list
T[] vals; //to store the contents
#SuppressWarnings("unchecked")
public MyArrayList() {
num = 0;
vals = (T[]) new Object[3];
}
public T getUnique(){
T distinct = null;
int count = 0;
for (int i=0; i<vals.length; i++){
distinct = vals[i];
for (int j = 0; j<vals.length; j++){
if (vals[j] == vals[i]){
count++;
}
if (count == 1){
return distinct;
}
}
}
if (distinct == null){
throw new IllegalArgumentException();
}
return distinct;
}
I am trying to work on a get Unique Method. A method getUnique that takes no arguments and returns the first value in the list that appears only once. (For example, calling the method on the list [1,2,3,1,2,4] would return 3 since 1 and
2 both appear more than once.) If the list is empty or all its values appear more than once, the method throws a NoSuchElementException
I have added some FIXME's to your code:
public T getUnique(){
T distinct = null;
int count = 0; // FIXME: move this initialization inside the i loop
for (int i=0; i<vals.length; i++){
distinct = vals[i];
for (int j = 0; j<vals.length; j++){
if (vals[j] == vals[i]){ // FIXME: use .equals() not ==
count++;
}
if (count == 1){ // FIXME: move this check outside the j loop
return distinct;
}
}
}
if (distinct == null){ //FIXME: no check needed, just throw it
throw new IllegalArgumentException();
}
return distinct; //FIXME: no valid return can reach this point
}
Patrick Parker's advice will fix your code, but I wanted to provide a cleaner and faster solution to the problem of finding a unique element in a list. This algorithm runs in time O(n) instead of O(n^2).
public static <T> Optional<T> getUnique(List<T> ls) {
// Create a map whose keys are elements of the list and whose values are
// lists of their occurences. E.g. [1,2,3,1,2,4] becomes {1->[1, 1],
// 2->[2, 2], 3->[3], 4->[4]}. Then elements.get(x).size() tells us how
// many times x occured in ls.
Map<T, List<T>> elements = ls.stream()
.collect(Collectors.groupingBy(x -> x));
// Find the first element that occurs exactly one time in ls.
return ls.stream().filter(x -> elements.get(x).size() == 1)
.findFirst();
}
You might call it like this:
Integer[] vals = {1,2,3,1,2,4};
System.out.println(getUnique(Arrays.asList(vals))
.orElseThrow(NoSuchElementException::new));
This code uses Java 8 streams and Optional. Below is another implementation of the same algorithm that doesn't use Java 8 language features; if you've never encountered streams, you may find it more understandable.
private static <T> T getUnique(List<T> arr) {
Map<T, Integer> numOccurrences = new HashMap<>();
for (T item : arr) {
numOccurrences.put(item, 1 + numOccurrences.getOrDefault(item, 0));
}
for (T item : arr) {
if (numOccurrences.get(item) == 1) {
return item;
}
}
throw new NoSuchElementException();
}
This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 6 years ago.
I need to create an array list using generics. My add method seems to work sometimes, however my get method appears to have a good amount of problems and i don't receive a compile error. However when i try to get an object from the Array list using my get method it throws a java out of bounds exception. here i what i have so far, and i am using BlueJ. Also, the instructions were to set the initial "illusion" length to zero.
public class AL <X> {
private X[]data;
private int count;
public AL() {
count = 0;
data = (X[]) new Object[0];
}
public void add (X v) {
if (data.length != count) {
data[count] = v;
count++;
} else {
X [] newdata = (X[]) new Object[data.length * 2];
for (int i = 0; i < data.length; i++) {
newdata[i] = data [i];
}
count++;
data = newdata;
}
}
public X get(int index) {
if (index >= count || index < 0) {
throw new ICantEven();
} else {
return data[index];
}
}
}
Your add method doesn't work, since the initial backing array you are using has a 0 length, which remains 0 even when you try to double it (since 0*2==0).
You also forgot to actually add the new element when you resize the backing array. If you hadn't forgot that, you'd get the exception in add.
First of all, change the initial size of the array created by your constructor to be positive :
data = (X[]) new Object[10];
Then add
data[count] = v;
to the else clause of your add method (just before count++;).
Your add method can be further simplified :
public AL()
{
count = 0;
data = (X[]) new Object[10];
}
public void add (X v)
{
// resize backing array if necessary
if (data.length == count)
{
X [] newdata = (X[]) new Object[data.length * 2];
for (int i = 0; i < data.length;i++ )
{
newdata[i] = data [i];
}
data = newdata;
}
// add new element
data[count] = v;
count++;
}
This code will not compile for me , can anyone fix it or see a problem with it?
I keep getting the error arraylistv2.java uses unchecked or unsafe operators,
when i added -Xlint it pointed to
private T[] seq = (T[])(new Object[1024]); // 1024 arbitrary
as the problem , any ideas?
class ArrayList<T>
{
private T[] seq = (T[])(new Object[1024]); // 1024 arbitrary
private int numItems = 0; // seq[0..numItems-1] significant
public int size() { return(numItems); }
public T get(int i)
{
if(i < 0 || i >= numItems)
throw new IndexOutOfBoundsException();
else
return seq[i];
}
public T set(int i, T t)
{
if(i < 0 || i >= numItems)
throw new IndexOutOfBoundsException();
else
{
T temp = seq[i];
seq[i] = t;
return temp;
}
}
public boolean add(T t)
{
add(numItems,t);
return true; // for compatibility reasons only
}
public void add(int i, T t)
{
if(i < 0 || i > numItems)
throw new IndexOutOfBoundsException();
if(numItems == seq.length)
resize(); // extend seq
for(int k = numItems; k > i; k--) // shift seq[i..] to right
seq[k] = seq[k-1];
seq[i] = t;
numItems++;
}
private void resize()
{ // seq is full -- double its size
T[] temp = (T[])(new Object[seq.length * 2]); // bigger array
for (int i = 0; i < seq.length; i++) // copy over items
temp[i] = seq[i];
seq = temp;
}
}
public class arraylistv2{
public static void main(String [] args){
ArrayList<String> arraylist1 = new ArrayList<String>();
arraylist1.add(1,"orange");
arraylist1.add(2,"apple");
int i = arraylist1.size();
System.out.println(arraylist1);
}
}
The message"arraylistv2.java uses unchecked or unsafe operators" is a warning not an error. In other words, there is no compile time error in your code. So, it should compile just fine (albeit with a couple of warning messages).
There is actually a runtime error in your code:
Exception in thread "main" java.lang.IndexOutOfBoundsException
at arraylistv2$ArrayList.add(arraylistv2.java:45)
at arraylistv2.main(arraylistv2.java:5)
Lastly, it seems that the type cast from object[] to T[] is not necessary in your code here:
private T[] seq = (T[])(new Object[1024]);
I'd recommend leaving it as a Object[]. All methods of your custom ArrayList class work with the generic type T so there is no way to put any other type of objects in seq anyways. Here is an example of custom ArrayList class that I wrote some time ago: https://github.com/anshulverma/nuaavee-collections/blob/master/src/main/java/com/nuaavee/collections/list/ArrayList.java
Hope that helps.
P.S. I should also point out that it is usually better to ask specific questions rather than pasting complete code listing. You will have more people responding to your questions that way. Not everyone has a lot of free time like me ;)
I'm a beginner and I have a problem with JUnit test in the constructor of a class.
The class that I want to test is called IntSortedArray and is as follows:
public class IntSortedArray {
private int[] elements;
private int size;
public IntSortedArray() {
this.elements = new int[16];
this.size = 0;
}
public IntSortedArray(int initialCapacity) throws IllegalArgumentException {
if(initialCapacity < 0) {
throw new IllegalArgumentException("Error - You can't create an array of negative length.");
}
else {
elements = new int[initialCapacity];
size = 0;
}
}
public IntSortedArray(int[] a) {
elements = new int[a.length + 16];
for(int i = 0; i < a.length; i++)
elements[i] = a[i];
size = a.length;
insertionSort(elements);
}
//other code...
}
With Eclipse I created a class for JUnit:
public class IntSortedArrayUnitTest {
private IntSortedArray isa;
#Test
public void testConstructorArray16Elements() {
isa = new IntSortedArray();
int expected = 0;
for(int i: isa.elements) **<-- ERROR**
expected += 1;
assertEquals(expected, 16);
}
}
I started to write a test class with the intention to test all the methods of the class IntSortedArray, including constructors.
The first method testConstructorArray16Elements() wants to test the first builder.
So I thought I would check if the creation of the array elements is done properly, so the for loop counts how long elements and make sure it along 16 (as required).
But Eclipse generates (rightly) a mistake because elements is private.
How can I fix this error? I don't want to put the public field and if possible I would like to avoid creating a method public int[] getElements().
What do you recommend?
Another question: I can do two assert the same method? One to test the length of the array and the other to test that size is 0.
I hope not to have made big mistakes, this is the first time I use JUnit.
PS: how can I test the second constructor?
Thank you very much!
It looks like your class fields are declare as private but you trying to access then from outside the class. You need to provide the accessors methods in you class to make them visible:
private int[] elements;
private int size;
public static final int MAX = 16;
public int[] getElements() { ... }
public int getSize() { return size; }
Then you will be able to write below code:
isa = new IntSortedArray();
int expected = 0;
for(int i: isa.getElements()) {
expected += 1;
}
assertEquals(expected, IntSortedArray.MAX );
It looks like your constructor has created an array for 16 integers, but does not initialize it with any value. To do that you should have below code:
public IntSortedArray() {
this.elements = new int[MAX];
this.size = 0;
for (int i=0 ; i < MAX ;i++) {
elements[i] = i;
size++;
}
}
You'll have to write a getter method for your array, or implement an Iterator