• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Paul Clapham
  • Ron McLeod
  • Tim Cooke
  • Junilu Lacar
Sheriffs:
  • Rob Spoor
  • Devaka Cooray
  • Jeanne Boyarsky
Saloon Keepers:
  • Jesse Silverman
  • Stephan van Hulst
  • Tim Moores
  • Carey Brown
  • Tim Holloway
Bartenders:
  • Jj Roberts
  • Al Hobbs
  • Piet Souris

Interface as a type

 
Ranch Foreman
Posts: 77
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Can someone please explain why is recommended to use List<E> as a a reference type when creating an ArrayList<E> instead of just using an ArrayList<E>?


versus


I need to see the power of doing this thing.
Many thanks
Antonio
 
Saloon Keeper
Posts: 8736
71
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
When you use List<T> on the left you are programming to a "higher level of abstraction". That is, an ArrayList in your example is a concrete class, whereas a List is an interface that cannot be constructed but defines the behaviors of ANY list type that implements it. The benefit to this is that you can come along at a later date and decide that a LinkedList would have been a better choice and swap it out without breaking a whole bunch of code.
 
Saloon Keeper
Posts: 1606
52
Eclipse IDE Postgres Database C++ Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This is "topologically equivalent" to places where you might choose a HashSet or TreeSet based on whether you cared about order for them or not.

When you are actually creating one with a new ArrayList<E>()  expression, you are overwhelmingly more likely to be using ArrayList<E> than LinkedList<E> in this case.

However, there are many, many, MANY things that are not of type ArrayList<E> that will wind up getting assigned to your List<E> references, we talked about those a LOT, probably too much in this thread:

https://coderanch.com/t/744952/java/ArrayList

If you breeze thru that and get far down, you will see that thinking that List, ArrayList, same thing basically...is way further from the truth than you are currently thinking.
Or that I was thinking when we started that big thread.

Cheers,
Jesse
 
Marshal
Posts: 16631
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
A couple of principles are involved here:

Depend on abstractions, not concretions. In other words, code to interfaces, not implementations.

Also, Liskov Substitution Principle which basically says that any code that works with type T should work with any S that is a subtype of T. In your example, List is the super type T and ArrayList is S which is a subtype of T.
 
Junilu Lacar
Marshal
Posts: 16631
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Antonio Moretti wrote:I need to see the power of doing this thing.


One advantage of doing this is that you can substitute one implementation for another at a later time. If you haven't violated the Liskov Substitution Principle (LSP), then the code should still work even if you use a different implementation of List. This may not seem like a huge advantage if you don't intend to change the implementation in production but it can help when you're testing. By programming to an interface, you can use mocks or stub implementations of the interfaces instead of the actual implementation. Reasons for wanting to do that include having more control over the behavior of the dependency and it can make test setup easier/simpler.
 
Junilu Lacar
Marshal
Posts: 16631
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
See also Why should I prefer programming to interfaces rather than implementations?
 
Jesse Silverman
Saloon Keeper
Posts: 1606
52
Eclipse IDE Postgres Database C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The things Junilu mentioned are very important and apply very generally.

We discussed some other issues that are specific to the List<> interface in Java in the thread I linked and some others, where you are quite likely to have a reference variable of declared type List<> but it may or may not be immutable, may or may not be fixed size, etc.

There were several important considerations that I wasn't thinking of going into that due to experience in other languages, mostly involving those kinds of situations applying to some List-like object that we would likely store in a List<> reference, where there are all kinds of things you could write involving one that would indeed compile fine, but go boom at runtime.

Some of those are more likely to be seen in recent Java versions.  For instance, List.of() has only been with us since Java 9, List.copyOf() has only been available since Java 10.

It is relatively easy for someone with lots of experience with earlier Java versions and not much with those newer than Java 8 to write code that will compile but not work the way they expected at Runtime.

These issues are somewhat orthogonal to Junilu's great advice, as they pertain to "Hey, what exactly do we mean by List<E> anyway??"  You can quite easily have something assigned to a List<> that has methods available you had better not call unless you are looking to crash, possibly in a logic-dependent or data-dependent way.

 
Master Rancher
Posts: 180
5
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Antonio Moretti wrote:I need to see the power of doing this thing.


It may help to look at it from this way:

When a class can be considered a blue print for objects - an interface can be seen as a general outline a class (as a blue print for objects) has to follow ... or somewhat along those lines.

An Interface is not just a language construct specific to Java - but a more overall design concept for programming in general.

May let me give you another example: Extensions, Plugins, Add-Ons, Mods ... or whatever you like to call it: pretty much anytime you add some additional 3rd-party stuff to an existing application. One of the best known examples: Browsers!
I'm not sure which came first, but Microsoft had pretty early on this ActiveX stuff. Firefox and then Chrome came with their extension apis. Even Java Applets and Flash were implemented as browser-plugins/-extensions ... and even HTML5 WEBm media stuff is just the next step of it.

And all that are pretty much general Interfaces and specific implementations.
 
Jesse Silverman
Saloon Keeper
Posts: 1606
52
Eclipse IDE Postgres Database C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Every response to the OP has been very valuable.

I will just say one more time, that the specific example you are encountering here, i.e. Java List<T> interface versus Java ArrayList<T> is not going to show the huge difference that the examples other people are giving you would.  It isn't the best example to show the power of coding to Interface rather than Implementation.

They covered the general idea very well, which applies to all areas of development and to languages other than Java just as well.  I focused on weird stuff that you should know about the difference between having a reference to a List<T> vs. ArrayList<T> that is very specific to those critters in the zoo of the Java Collections Framework.  If you think of your List<T> just as a theoretically more abstract and preferable way to refer to an ArrayList<T> there are numerous ways you can get burned, because it can also refer to things that are decidedly NOT ArrayList<T> as well.


 
Antonio Moretti
Ranch Foreman
Posts: 77
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:

Antonio Moretti wrote:I need to see the power of doing this thing.


One advantage of doing this is that you can substitute one implementation for another at a later time. If you haven't violated the Liskov Substitution Principle (LSP), then the code should still work even if you use a different implementation of List. This may not seem like a huge advantage if you don't intend to change the implementation in production but it can help when you're testing. By programming to an interface, you can use mocks or stub implementations of the interfaces instead of the actual implementation. Reasons for wanting to do that include having more control over the behavior of the dependency and it can make test setup easier/simpler.



Isn't there a big risk you will violate Liskov if you are just doing List as the reference variable every time you make an ArrayList object? Teachers say we should do this but do not give good explain why. Also, as rule of thumb be taught to go for the highest abstraction, so here why not use Collection?
 
Junilu Lacar
Marshal
Posts: 16631
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Antonio Moretti wrote:Isn't there a big risk you will violate Liskov if you are just doing List as the reference variable every time you make an ArrayList object? Teachers say we should do this but do not give good explain why. Also, as rule of thumb be taught to go for the highest abstraction, so here why not use Collection?


What risk would that be? As to going with Collection instead of List, that depends on the context. You have to balance which interface you use with the task you need to use it for.
 
Marshal
Posts: 74342
334
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
If you need duplicate elements, you will have problems with something declared as Collection; some Collections, e.g. Lists, do support duplicates, and some, e.g. Sets, don't. Lists implicitly record insertion order as do some Set implementations, e.g. this one, but others, e.g. this don't.
So Collection is only useful as a declared type in certain restricted circumstances.
 
Matthew Bendford
Master Rancher
Posts: 180
5
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
As for List vs Collection:
Although an ArrayList has several advantages over othe implementations, and seem to be the preferred one, currently I use LinkedList a lot.
Although both implement Collection as well as List I often rely on the specifics of Queue or rarely even Deque wich neither List nor Collection offer - but I still use these Interfaces as types instead of LinkedList directly cause maybe at some time I need to change to ArrayDeque or even something else.
It's just one specific example, but it shows that sometimes one can't get away with such a high abstract Interface but do need some more specific while still keep the possibility to interchange concrete implementations.
 
Campbell Ritchie
Marshal
Posts: 74342
334
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Does ArrayDeque implement List? No, it doesn't. You couldn't use Collection as a Queue, Deque, or Stack because it lacks the requisite methods. Sun have been recommending you migrate to ArrayDeque since Java6.
 
Matthew Bendford
Master Rancher
Posts: 180
5
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:Does ArrayDeque implement List? No, it doesn't. You couldn't use Collection as a Queue, Deque, or Stack because it lacks the requisite methods. Sun have been recommending you migrate to ArrayDeque since Java6.


I haven't looked at the docs ArrayDeque but only saw it listed as implementing Deque. So I just threw it in as a possible alternative for Queue or Deque, not so much as another List implementation. Also: I refered with "both implement List" to ArrayList vs LinkedList.
As for the small font line: In which use cases?
 
Campbell Ritchie
Marshal
Posts: 74342
334
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Matthew Bendford wrote:. . . In which use cases?

For everything, provided the following isn't an issue:-

Null elements are prohibited.

Stack's documentation wrote:A more complete and consistent set of LIFO stack operations is provided by the Deque interface and its implementations, which should be used in preference to this class. For example:

 
  Deque<Integer> stack = new ArrayDeque<Integer>();

Java™ Tutorials. This is only a recommendation, not some sort of requirement.
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic