10
10
import java .util .stream .StreamSupport ;
11
11
12
12
/**
13
- * This class implements a dynamic array
13
+ * This class implements a dynamic array.
14
14
*
15
15
* @param <E> the type that each index of the array will hold
16
16
*/
17
17
public class DynamicArray <E > implements Iterable <E > {
18
18
19
19
private static final int DEFAULT_CAPACITY = 16 ;
20
-
21
- private int capacity ;
22
20
private int size ;
21
+ private int modCount ; // Tracks structural modifications for the iterator
23
22
private Object [] elements ;
24
23
25
24
/**
26
- * constructor
25
+ * Constructor with initial capacity.
27
26
*
28
27
* @param capacity the starting length of the desired array
28
+ * @throws IllegalArgumentException if the specified capacity is negative
29
29
*/
30
30
public DynamicArray (final int capacity ) {
31
+ if (capacity < 0 ) {
32
+ throw new IllegalArgumentException ("Capacity cannot be negative." );
33
+ }
31
34
this .size = 0 ;
32
- this .capacity = capacity ;
33
- this .elements = new Object [this . capacity ];
35
+ this .modCount = 0 ;
36
+ this .elements = new Object [capacity ];
34
37
}
35
38
36
39
/**
37
- * No-args constructor
40
+ * No-args constructor with default capacity.
38
41
*/
39
42
public DynamicArray () {
40
43
this (DEFAULT_CAPACITY );
41
44
}
42
45
43
46
/**
44
- * Adds an element to the array If full, creates a copy array twice the size
45
- * of the current one
47
+ * Adds an element to the array. If full, creates a new array with double the size.
46
48
*
47
- * @param element the element of type <E> to be added to the array
49
+ * @param element the element to be added to the array
48
50
*/
49
51
public void add (final E element ) {
50
- if (this .size == this .elements .length ) {
51
- this .elements = Arrays .copyOf (this .elements , newCapacity (2 * this .capacity ));
52
- }
53
-
54
- this .elements [this .size ] = element ;
55
- size ++;
52
+ ensureCapacity (size + 1 );
53
+ elements [size ++] = element ;
54
+ modCount ++; // Increment modification count
56
55
}
57
56
58
57
/**
59
- * Places element of type <E> at the desired index
58
+ * Places an element at the desired index, expanding capacity if necessary.
60
59
*
61
- * @param index the index for the element to be placed
60
+ * @param index the index for the element to be placed
62
61
* @param element the element to be inserted
62
+ * @throws IndexOutOfBoundsException if n is less than 0 or greater or equal to the number of elements in the array
63
63
*/
64
64
public void put (final int index , E element ) {
65
- this .elements [index ] = element ;
65
+ if (index < 0 ) {
66
+ throw new IndexOutOfBoundsException ("Index cannot be negative." );
67
+ }
68
+ ensureCapacity (index + 1 );
69
+ elements [index ] = element ;
70
+ if (index >= size ) {
71
+ size = index + 1 ;
72
+ }
73
+ modCount ++; // Increment modification count
66
74
}
67
75
68
76
/**
69
- * get method for element at a given index returns null if the index is
70
- * empty
77
+ * Gets the element at a given index.
71
78
*
72
79
* @param index the desired index of the element
73
- * @return <E> the element at the specified index
80
+ * @return the element at the specified index
81
+ * @throws IndexOutOfBoundsException if n is less than 0 or greater or equal to the number of elements in the array
74
82
*/
83
+ @ SuppressWarnings ("unchecked" )
75
84
public E get (final int index ) {
76
- return getElement (index );
85
+ if (index < 0 || index >= size ) {
86
+ throw new IndexOutOfBoundsException ("Index: " + index + ", Size: " + size );
87
+ }
88
+ return (E ) elements [index ];
77
89
}
78
90
79
91
/**
80
- * Removes an element from the array
92
+ * Removes an element from the array.
81
93
*
82
94
* @param index the index of the element to be removed
83
- * @return <E> the element removed
95
+ * @return the element removed
96
+ * @throws IndexOutOfBoundsException if n is less than 0 or greater or equal to the number of elements in the array
84
97
*/
85
98
public E remove (final int index ) {
86
- final E oldElement = getElement (index );
87
- fastRemove (this .elements , index );
88
-
89
- if (this .capacity > DEFAULT_CAPACITY && size * 4 <= this .capacity ) {
90
- this .elements = Arrays .copyOf (this .elements , newCapacity (this .capacity / 2 ));
99
+ if (index < 0 || index >= size ) {
100
+ throw new IndexOutOfBoundsException ("Index: " + index + ", Size: " + size );
91
101
}
102
+ @ SuppressWarnings ("unchecked" ) E oldElement = (E ) elements [index ];
103
+ fastRemove (index );
104
+ modCount ++; // Increment modification count
92
105
return oldElement ;
93
106
}
94
107
95
108
/**
96
- * get method for size field
109
+ * Gets the size of the array.
97
110
*
98
- * @return int size
111
+ * @return the size
99
112
*/
100
113
public int getSize () {
101
- return this . size ;
114
+ return size ;
102
115
}
103
116
104
117
/**
105
- * isEmpty helper method
118
+ * Checks if the array is empty.
106
119
*
107
- * @return boolean true if the array contains no elements, false otherwise
120
+ * @return true if the array contains no elements, false otherwise
108
121
*/
109
122
public boolean isEmpty () {
110
- return this . size == 0 ;
123
+ return size == 0 ;
111
124
}
112
125
113
126
public Stream <E > stream () {
114
127
return StreamSupport .stream (spliterator (), false );
115
128
}
116
129
117
- private void fastRemove (final Object [] elements , final int index ) {
118
- final int newSize = this .size - 1 ;
119
-
120
- if (newSize > index ) {
121
- System .arraycopy (elements , index + 1 , elements , index , newSize - index );
130
+ private void ensureCapacity (int minCapacity ) {
131
+ if (minCapacity > elements .length ) {
132
+ int newCapacity = Math .max (elements .length * 2 , minCapacity );
133
+ elements = Arrays .copyOf (elements , newCapacity );
122
134
}
123
-
124
- this .size = newSize ;
125
- this .elements [this .size ] = null ;
126
135
}
127
136
128
- private E getElement (final int index ) {
129
- return (E ) this .elements [index ];
130
- }
131
-
132
- private int newCapacity (int capacity ) {
133
- this .capacity = capacity ;
134
- return this .capacity ;
137
+ private void fastRemove (int index ) {
138
+ int numMoved = size - index - 1 ;
139
+ if (numMoved > 0 ) {
140
+ System .arraycopy (elements , index + 1 , elements , index , numMoved );
141
+ }
142
+ elements [--size ] = null ; // Clear to let GC do its work
135
143
}
136
144
137
- /**
138
- * returns a String representation of this object
139
- *
140
- * @return String a String representing the array
141
- */
142
145
@ Override
143
146
public String toString () {
144
- return Arrays .toString (Arrays .stream ( this . elements ). filter ( Objects :: nonNull ). toArray ( ));
147
+ return Arrays .toString (Arrays .copyOf ( elements , size ));
145
148
}
146
149
147
- /**
148
- * Creates and returns a new Dynamic Array Iterator
149
- *
150
- * @return Iterator a Dynamic Array Iterator
151
- */
152
150
@ Override
153
151
public Iterator <E > iterator () {
154
152
return new DynamicArrayIterator ();
@@ -157,71 +155,50 @@ public Iterator<E> iterator() {
157
155
private final class DynamicArrayIterator implements Iterator <E > {
158
156
159
157
private int cursor ;
158
+ private int expectedModCount ;
159
+
160
+ DynamicArrayIterator () {
161
+ this .expectedModCount = modCount ;
162
+ }
160
163
161
164
@ Override
162
165
public boolean hasNext () {
163
- return this .cursor != size ;
166
+ checkForComodification ();
167
+ return cursor < size ;
164
168
}
165
169
166
170
@ Override
171
+ @ SuppressWarnings ("unchecked" )
167
172
public E next () {
168
- if (this .cursor > DynamicArray .this .size ) {
173
+ checkForComodification ();
174
+ if (cursor >= size ) {
169
175
throw new NoSuchElementException ();
170
176
}
171
-
172
- if (this .cursor > DynamicArray .this .elements .length ) {
173
- throw new ConcurrentModificationException ();
174
- }
175
-
176
- final E element = DynamicArray .this .getElement (this .cursor );
177
- this .cursor ++;
178
-
179
- return element ;
177
+ return (E ) elements [cursor ++];
180
178
}
181
179
182
180
@ Override
183
181
public void remove () {
184
- if (this . cursor < 0 ) {
182
+ if (cursor <= 0 ) {
185
183
throw new IllegalStateException ();
186
184
}
185
+ checkForComodification ();
186
+ DynamicArray .this .remove (--cursor );
187
+ expectedModCount = ++modCount ;
188
+ }
187
189
188
- DynamicArray .this .remove (this .cursor );
189
- this .cursor --;
190
+ private void checkForComodification () {
191
+ if (modCount != expectedModCount ) {
192
+ throw new ConcurrentModificationException ();
193
+ }
190
194
}
191
195
192
196
@ Override
193
197
public void forEachRemaining (Consumer <? super E > action ) {
194
198
Objects .requireNonNull (action );
195
-
196
- for (int i = 0 ; i < DynamicArray .this .size ; i ++) {
197
- action .accept (DynamicArray .this .getElement (i ));
199
+ while (hasNext ()) {
200
+ action .accept (next ());
198
201
}
199
202
}
200
203
}
201
-
202
- /**
203
- * This class is the driver for the DynamicArray<E> class it tests a variety
204
- * of methods and prints the output
205
- */
206
- public static void main (String [] args ) {
207
- DynamicArray <String > names = new DynamicArray <>();
208
- names .add ("Peubes" );
209
- names .add ("Marley" );
210
-
211
- for (String name : names ) {
212
- System .out .println (name );
213
- }
214
-
215
- names .stream ().forEach (System .out ::println );
216
-
217
- System .out .println (names );
218
-
219
- System .out .println (names .getSize ());
220
-
221
- names .remove (0 );
222
-
223
- for (String name : names ) {
224
- System .out .println (name );
225
- }
226
- }
227
204
}
0 commit comments