25

This Q is to look for a sample case where a generic array is absolutely necessary.

Generics and arrays "don't mix well".

Is there a case where a generic ArrayList won't do-- a generic array has no substitute and has to be used.

Effective Java leaves a door open for generic arrays saying that there may be cases where a generic array is necessary.

I've been using ArrayList without any shortcomings and can't think of a case like this.

TIA.

Note: i've seen these:

Along with some other discussions.

Community
  • 1
  • 1
Roam
  • 4,511
  • 9
  • 36
  • 68
  • 7
    Guess it depends on your requirements. In general, an `ArrayList` provides the same functionality as an array does. Maybe you need to satisfy some interface which requires arrays? Maybe you have some kind of performance or memory restriction? – fxnn May 13 '15 at 14:18
  • 1
    Are you talking about functionality? What do you mean by "absolutely necessary?" Generics have to do with compile-time type safety, not runtime functionality. – MadConan May 13 '15 at 14:20
  • 1
    What do you mean by generic ArrayList? do you mean ArrayList with generic element type? – MaxZoom May 13 '15 at 14:20
  • My vote would be on having to use a library that requires generic arrays. – biziclop May 13 '15 at 14:20
  • @fxnn - could be in the integrated code - yes. what do you mean by performance/mem.restrictions? ArrayList is an array-- direct memoru access n runs in the same complexity – Roam May 13 '15 at 14:23
  • ArrayList is not an array, it is a class implementing List, backed by an array. Which means that it has a (slightly) bigger memory footprint than an array, and is slightly slower. However, it gives a lot more functionality than a 'bare' array, so it is widely preferred. Also, to expose the internal array of an ArrayList, is just a matter of `myArrayList.toArray(new MyObject[] {});` – francesco foresti May 13 '15 at 14:29
  • 1
    @Roam: well, though many people (including me) consider this as micro optimization, arrays *are* faster than `ArrayList`s. See [this answer](http://stackoverflow.com/a/16565376/3281722), where the poster stated that getting and setting elements is 25% resp. 40% faster for arrays. Still, we're talking of operations being so fast that in usual use cases, no one would ever mind. – fxnn May 13 '15 at 14:30
  • 2
    What do you mean by "generic array" here? Like a hypothetical checked & reified array like `new T[n]` (which doesn't exist but might be useful for things), an unchecked array like `(T[])new Object[n]` or an array of a raw type & unchecked parameterization like `Map.Entry[]`? All of these are sometimes called "generic arrays" but they're really different things. – Radiodef May 13 '15 at 14:35
  • @fxnn 40% is big. must be the method calls in between. in any case, it's in the same asymptotic "zone" as arrays. – Roam May 13 '15 at 14:47
  • 1
    Also note that we could just as legitimately reverse the question and ask *"When is an ArrayList absolutely necessary over an array?"* And the answer is never: C programmers have done just fine for years without ArrayList. – Radiodef May 13 '15 at 18:55
  • 2
    What about implementing an `ArrayList`? Hard to use an `ArrayList` then. – Boris the Spider May 13 '15 at 19:45

8 Answers8

7

Some points:

  • If you have some "legacy" library then you're bound to the types that they use. This could be arrays.

  • If you handle native code then arrays will be a more natural way to exchange data with the native code.

  • If you access binary data (e.g. sound files or similar) then using an array can help.

  • If you handle big amount of binary data then an array could be more efficient.

So there are many reasons why an array could be helpful (especially with primitive types).

If you only handle objects then it is most times easier to use a List.

Uwe Plonus
  • 9,235
  • 4
  • 36
  • 47
6

I would say that Bloch meant convenient instead of necessary, arrays are simpler structures, easier to handle.

As a data structure, from a functionalities point of view, ArrayList are interchangeable with array.

Arrays are obviously more lean memory-wise but require additional effort to get some basic functionalities (i.e. manual array resizing when the original array is not big enough to hold a new element) but other functions are already provided by the runtime (Arrays class).

ArrayLists are backed by actual Object arrays so there isn't much difference performance wise, for common operations like searching and sorting (when using the same algorithm).

Umberto Raimondi
  • 16,269
  • 7
  • 44
  • 54
  • *"arrays are simpler structures,* ***easier*** *to handle."*; Really ? I'm curious about your explanation on how it is easier to handle the removal of an object at a specified index using array vs ArrayList. – Jean-François Savard May 13 '15 at 19:48
  • [LONG] I wasn't referring to removal (that's clearly way more convoluted to do manually on a statically sized array than just calling a remove method on a List object that implements the logic for you) or to any other specific operation. I wrote that, and i agree that is a bit empty as a statement, while i was considering two things that i had initially included in my answer: 1- How easy is to fill a generic list with the content of an array vs how more complex is the implementation of the typical toArray when you have an object that contains some data with parametrized type. – Umberto Raimondi May 13 '15 at 20:19
  • [Cont...] 2- After reading something about the native side in another answer, how arrays are easier (lines of code) to instantiate/use on the native side compared to lists. *So,* not relevant enough to define the array as outright *easier to handle*? Maybe yes. – Umberto Raimondi May 13 '15 at 20:19
3

Some loose thoughts:

array is a basic data type that's necessary in any imperative language (maybe in a disguised form). Without array, how can we implement ArrayList?:)

However, we could have disguised array as a "normal" type. For exmple, we could introduce a intrinsic lang.lang.Array<E> type that does array things, and eliminate the current array type in Java. (Ignoring primitive arrays, that's another topic). Everything will work out fine.

Yet, we don't have the luxury to "improve" and "clean" the language in a way that breaks backward compatibility.

Before the introduction of generics, array can be seen as a poor man's generics. We couldn't express ArrayList<String>, but we could do String[]. That is why a lot of old APIs return an array, instead of some collection type, because array was more type-safe. array is even co-variant ... sort of.

After the introduction of generics, the use cases for array become far fewer. Usually, you should avoid using array in a public API. (Of course, except for var-arg foo(Bar...) which is array under the hood)

But in the implementation code, we still need array, it's the basic data structure to build more complex data structures. For that purpose ArrayList is obviously more bloated in many cases.

Now, the question is, to implement something like ArrayList<E>, should we use a E[], or Object[] internally? Due to erasure, E[] is more troublesome - as the saying goes "generics and arrays don't mix well". So forget it, just use Object[] and do the cast when necessary.

ZhongYu
  • 18,232
  • 5
  • 28
  • 55
  • *"For ex* ***e*** *mple, we could introduce a intrinsic lang.lang.Array"* type that does array things, and eliminate the current array type in Java. Do you mean `ArrayList` ? – Jean-François Savard May 13 '15 at 19:50
  • @Jean-FrançoisSavard - no, ArrayList is more complicated - for example, its size can grow. – ZhongYu May 13 '15 at 20:27
  • And how does it make it harder to handle ? – Jean-François Savard May 13 '15 at 21:02
  • @Jean-FrançoisSavard - a language needs some basic data types, upone which more complicated data types can be built. ArraysList is not "basic" enough for that role. – ZhongYu May 13 '15 at 21:07
  • Well yes, but you specified yourself *"and eliminate the current array type in Java"*. – Jean-François Savard May 13 '15 at 21:27
  • @Jean-FrançoisSavard - I mean to replace array types `Object[], String[] etc` with an `Array` class - if we could redesign the language. This way, the language is simpler. – ZhongYu May 13 '15 at 21:29
  • I still don't think it's simpler. Generics are not to be used everywhere, simply when you have to. Imagine if you remove all Object types, you will have to verify yourself the type of each object to avoid classcast etc. – Jean-François Savard May 13 '15 at 21:35
  • @Jean-FrançoisSavard - this is, of course, subjective. My opinion is that, the language spec spends a lot of texts on array types; we could remove all that. – ZhongYu May 13 '15 at 21:44
3

An ArrayList requires a small amount of extra memory as compared to an array. This is obviously true as an ArrayList is implemented as a wrapper around an array. By my rough estimation, an ArrayList will consume an additional 16 bytes.

Under normal circumstances, this is nothing to worry about. But if you're creating a very large number of arrays (millions/billions), it could potentially make a difference.

There is also the case of primitive arrays. ArrayList is constrained by the rules for collections, so it cannot store primitive elements, only the corresponding object wrapper. So for example, byte[] consumes 1 byte per element, but ArrayList<Byte> consumes 4 bytes per element. This can make a difference if your arrays are potentially very large.

Kevin K
  • 9,050
  • 2
  • 34
  • 58
3

Generally, the ArrayList is considered to be more favourable than arrays. It provides the same functionality, while integrating better, especially with other types from the Java Collection API.

Therefore, the use of arrays could result out of special requirements. On the one hand, one may want to use a library (or other 3rd party code) which requires arrays.

One the other hand, arrays still perform better than an ArrayList. I created a Gist which compares the use of an ArrayList<Integer> to an int[]. (Note, that you can't use primitives with ArrayLists.) The average results for creating 1.000.000 random elements and finding their maximum on my machine:

Test case CREATE_ARRAY average time: 25.93 ms
Test case CREATE_ARRAY_LIST average time: 44.06 ms
Test case MAX_OVER_ARRAY average time: 1.44 ms
Test case MAX_OVER_ARRAY_LIST average time: 5.86 ms

So, we're roundabout 4 times slower with an ArrayList. Yet, in normal use cases, this can safely be considered as micro optimization. Most use cases demand code quality over such performance improvements.

fxnn
  • 652
  • 5
  • 16
  • Insertion is slower because internally ArrayList is actually resizing its backing array *a lot* of times (each time the initial size is doubled). With a meaningful initial size, performance should be nearly the same. – Umberto Raimondi May 13 '15 at 15:06
  • You seem to be starting with a "cold" VM, do the times still look similar once the calls are inlined? – biziclop May 13 '15 at 15:14
  • @user43250937: Look at the code, I start with the right capacity. No resizing involved. – fxnn May 13 '15 at 15:15
  • @biziclop: I'm repeating the same test (1,000,000 elements) a hundred times, and what you see are average results. Indeed, times change from (485, 21, 55, 13) in the first run to (28, 71, 1, 9) in the last run. – fxnn May 13 '15 at 15:17
  • 1
    Ok, just saw the gist. Inlining of `add` on Hotspot should be performed after 10k invocations, test accordingly :) – Umberto Raimondi May 13 '15 at 15:23
2

[...] saying that there may be cases where a generic array is necessary.

It seems like Joshua Bloch simply wanted to be safe allowing a possibility even if he don't know one.

Why would an author mention such a point without an example if he knows there is one ?

Assuming ArrayList store it values itself in an array and only provides useful method so that you don't have to re-write everything, I would be highly suprised to face a case where you can't achieve something with an ArrayList but can achieve with an array.

The data structure itself is the same, remember Arrays.asList and ArrayList.toArray

Umberto Raimondi
  • 16,269
  • 7
  • 44
  • 54
Jean-François Savard
  • 19,624
  • 6
  • 42
  • 70
1

Generics is for not needing to rewrite code when using different objects in an array, or when holding child instances and not being able to cast in a loop for example. you let classes and interfaces be parameters in other classes.

oracle tutorials

Elimination of casts. The following code snippet without generics requires casting:

List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);

When re-written to use generics, the code does not require casting:

List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0);   // no cast
MRK187
  • 1,277
  • 2
  • 11
  • 19
  • How does this answer the question *"When is a generic array absolutely necessary?"* – Radiodef May 13 '15 at 18:53
  • My point is at sometimes you reach a point when you can't cast something because it will be set during runtime, – MRK187 May 13 '15 at 19:41
1

I thought of a couple things immediately when I read the question.

One: If you're using Java Micro Edition, you may not have ArrayList available to you. This kind of thing is fairly common if you ever work on legacy code. Writing in .Net 1.1 or 2.0 feels a lot like cutting your arms off compared to 4.0 and later(in my opinion). Java Micro Edition is similar - If you're used to Java 6+ then J2ME feels really restrictive. This question discusses it a bit, but I think I'd go with a regular array than use a vector(which according to that thread is synchronized...I haven't delved deeper than that).

Two: If you're on an embedded system and need to have tight control over the size of the array. Other answers touched on this a bit. IIrc the default functionality of ArrayList is to double in size when it resizes, but I'm having trouble finding an exact quote on that. On embedded systems with very limited memory, it wouldn't surprise me if such a resize tried to allocate more than all the memory in the system(eg your array takes up 75% of all system memory, on a resize it'll try to take up 150% of the memory). If you use an array and manually control all resizes, then this becomes a non-issue.

Community
  • 1
  • 1
Shaz
  • 1,347
  • 8
  • 18
  • you must be a C developer. :) never coded in JME that far - however, can see your point. embedded is better on C/C++ all the way. – Roam May 13 '15 at 17:36