Revisit: List list = new ArrayList();

K

Knute Johnson

I saw some code go by today that was;

Writer fw = new FileWriter(--- // since ... confuses some people

I know we had a discussion the other day about;

List list = new ArrayList();

and why you would do that. I'm curious as to how many people would do
the above with FileWriter, BufferedOutputStream, or FileOutputStream.

And why would you not;

Collection c = new ArrayList();

The other question I had is what do you call that? Is it a cast? A
sort of implicit cast across assignment? Is it mentioned in the JLS
someplace?

I'm not trying to get anyone's knickers in a twist with this, I'm just
curious, so please don't take it for anything more than that.

Thanks,
 
L

Lew

Knute said:
I saw some code go by today that was;

Writer fw = new FileWriter(--- // since ... confuses some people

I know we had a discussion the other day about;

List list = new ArrayList();

and why you would do that. I'm curious as to how many people would do
the above with FileWriter, BufferedOutputStream, or FileOutputStream.

It depends. I've done that, but not always. The best practice is to declare
a variable to be the most general type suitable to its purpose. Writer might
lack a method that, say, PrintWriter has, and thus you'd not declare a
variable Writer if you needed that extra method.

If you don't need the specific behavior, then you absolutely should declare
the variable to be of the more general type.
And why would you not;

Collection c = new ArrayList();

You might need "c" to be a list - ordered, permissive of duplicates and
index-accessible.
The other question I had is what do you call that? Is it a cast? A
sort of implicit cast across assignment? Is it mentioned in the JLS
someplace?

Upcast. The technical name is a "widening reference conversion".
<http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.1.5>

Joshua Bloch has a tip about this in his seminal /Effective Java/.
 
O

Owen Jacobson

I saw some code go by today that was;

Writer fw = new FileWriter(--- // since ... confuses some people

I know we had a discussion the other day about;

List list = new ArrayList();

and why you would do that. I'm curious as to how many people would do
the above with FileWriter, BufferedOutputStream, or FileOutputStream.

And why would you not;

Collection c = new ArrayList();

The other question I had is what do you call that? Is it a cast? A
sort of implicit cast across assignment? Is it mentioned in the JLS
someplace?

It's an implicit widening reference conversion (5.1.5):

--\--
A widening reference conversion exists from any type S to any type T,
provided S is a subtype (§4.10) of T.

Widening reference conversions never require a special action at run
time and therefore never throw an exception at run time. They consist
simply in regarding a reference as having some other type in a manner
that can be proved correct at compile time.

See §8 for the detailed specifications for classes, §9 for interfaces,
and §10 for arrays.
--/--

The type of the variable carries around some documentation of what
promises the code expects from the referenced object. In the case of
List<T>, I try to use the most general interface I can; if I need
get(int) but don't care much about the run time, then obviously it's
got to be a List<T> since indexed get is not provided by
Collection<T>, but if all I'm doing is iterating over the contents
then Iterable<T> might suffice (being slightly more general than
Collection<T>). If the algorithm I'm writing relies on O(1) seek
time, then I'd declare it as ArrayList (in the absence of a
"ConstantTimeSeekingList" interface :).

With the stream decorator patterns I categorize things into sources
(which I pass around as Reader or InputStream instances) and
processors (which I pass around very little, and declare as their
concrete type). Source streams provide the basic stream, and should
be pretty much interchanable, but processors include things like
BufferedReader that provide features not available from the basic
Stream/Reader interfaces.

-O
 
R

Roedy Green

And why would you not;

Collection c = new ArrayList();

because List has ordering/random indexed access methods missing from
Collection, e.g. set(int index, E element);

If you did not need the random indexed access, Collection would be
appropriate. The theory is you use the interface/class with the
smallest number of methods that still lets you get the job done.
 
R

Roedy Green

The other question I had is what do you call that? Is it a cast? A
sort of implicit cast across assignment? Is it mentioned in the JLS
someplace?

Every Dalmatian is automatically a Dog. You can use a Dog reference
to a Dalmatian, but you can only use the Dog methods. This is
explained in every basic Java text book. Someone else might point you
to the lawyerese version of it in the JLS.

see http://mindprod.com/jgloss/dalmatian.html
 
R

Roedy Green

and why you would do that. I'm curious as to how many people would do
the above with FileWriter, BufferedOutputStream, or FileOutputStream.

Because when you use a FileWriter, BufferedOutputStream,
BufferedOutputStream, etc you often need access to all the specific
methods.

For example you would not write:

Writer caw = new CharArrayWriter(1000);

because you could not write:

char[] results = caw.toCharArray();

The catch is the various flavours of Writers are not quite as
interchangeable as Collections or Lists. The interfaces they implement
are primarily documentation to group similar classes.
 
P

Patricia Shanahan

Knute Johnson wrote:
....
Collection c = new ArrayList();

The other question I had is what do you call that? Is it a cast? A
sort of implicit cast across assignment? Is it mentioned in the JLS
someplace?
....

It is assignment conversion, mentioned in the description of the simple
assignment operator at
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.26.1

"A compile-time error occurs if the type of the right-hand operand
cannot be converted to the type of the variable by assignment conversion
(§5.2)."

Assignment conversion, defined in section 5.2, can be any of:

# an identity conversion (§5.1.1)
# a widening primitive conversion (§5.1.2)
# a widening reference conversion (§5.1.5)
# a boxing conversion (§5.1.7) optionally followed by a widening
reference conversion
# an unboxing conversion (§5.1.8) optionally followed by a widening
primitive conversion.

In this particular case, it is a widening reference conversion.

Patricia
 
M

Mike Schilling

Knute said:
I saw some code go by today that was;

Writer fw = new FileWriter(--- // since ... confuses some people

A bit off the point, but FileWriter and FileReader are evil and/or useless,
since they don't allow an encoding to be specified. The proper way to
create a Writer that writes to files is

new OutputStreamWriter(new FileOutputStream(file), encoding)
 
L

lyallex

Knute said:
I saw some code go by today that was;

Writer fw = new FileWriter(--- // since ... confuses some people

I know we had a discussion the other day about;

List list = new ArrayList();

and why you would do that. I'm curious as to how many people would do
the above with FileWriter, BufferedOutputStream, or FileOutputStream.

And why would you not;

Collection c = new ArrayList();

I didn't read the earlier discussion so may be going over old ground

One really cool thing about interface polymorphism is that it allows you
to write components that provide clients with an abstraction, leaving
room in the brain for the things that really matter.

A component with a published interface of (say)

public List foo() tells clients that they are getting a List and should
only do List like things with it. They probably have more important
things to worry about than your implementation of the component

Internally to foo() of course I may decide to use an ArrayList to do my
work then I might use List l = new ArrayList(). Why might I do this ?

Well if, in the future some fancy new component comes along that can do
List type things in a much more efficient
way I might like to change my internal implementation to use this new
component, I certainly don't want to change the published interface as
this might break all sorts of things.

Of course I could still do ArrayList l = new ArrayList() but then when I
wanted to change I'd need to be sure that all internal references to l
were capable of handling the new type,
Of course a long as the new wizzy list thingy still implemented List the
published interface would remain unchanged.

You ask about Writer fw = new FileWriter

Well, same reason really, what happens when you decide to change your
implementation to use the new VeryFancyTCPNetworkStorageWriter class,
all your clients care about is that now they can write much faster
and that they don't need such a big disk (or whatever).
They certainly don't want to hunt down every reference to your component
and change things because you have decided to change the internal
implementation.

Anyway, just my 3 groats worth.
 
P

Patricia Shanahan

Knute Johnson wrote:
....
And why would you not;

Collection c = new ArrayList();

ArrayList seems an unfortunate choice of implementing class, given the
code only needs the common features of Collection. ArrayList makes some
insertions and removals expensive for the sake of efficient indexed
access. Why pay that cost if you don't need indexed access?

Collection does not make it clear whether duplicates are allowed or not,
so I would usually use either List or Set instead.

Patricia
 
K

Knute Johnson

Patricia said:
Knute Johnson wrote:
...

ArrayList seems an unfortunate choice of implementing class, given the
code only needs the common features of Collection. ArrayList makes some
insertions and removals expensive for the sake of efficient indexed
access. Why pay that cost if you don't need indexed access?

Collection does not make it clear whether duplicates are allowed or not,
so I would usually use either List or Set instead.

Patricia

From the docs:

Collection

The JDK does not provide any direct implementations of this interface:
it provides implementations of more specific subinterfaces like Set and
List. This interface is typically used to pass collections around and
manipulate them where maximum generality is desired.

So wouldn't that suggest that Collection should be used instead of List?
 
D

Daniel Pitts

Patricia said:
Knute Johnson wrote:
....

ArrayList seems an unfortunate choice of implementing class, given the
code only needs the common features of Collection. ArrayList makes some
insertions and removals expensive for the sake of efficient indexed
access. Why pay that cost if you don't need indexed access?

Collection does not make it clear whether duplicates are allowed or not,
so I would usually use either List or Set instead.

Patricia
Although, perhaps you only need to collect things, and leave it to the
generator of the Collection instance whether they want duplication
allowed or ordering.

I think the line would be better off as
Collection c = getSomeThings();

Now, someThings may decide to return a list, set, or some other
implementation of Collection.
 
K

Knute Johnson

Patricia said:
Knute Johnson wrote:
...

ArrayList seems an unfortunate choice of implementing class, given the
code only needs the common features of Collection. ArrayList makes some
insertions and removals expensive for the sake of efficient indexed
access. Why pay that cost if you don't need indexed access?

Collection does not make it clear whether duplicates are allowed or not,
so I would usually use either List or Set instead.

Patricia

And one more question and I'll let this go back to where it was.

Is there any reason to do this for classes created on the stack?
 
H

Hendrik Maryns

Knute Johnson schreef:
From the docs:

Collection

The JDK does not provide any direct implementations of this interface:
it provides implementations of more specific subinterfaces like Set and
List. This interface is typically used to pass collections around and
manipulate them where maximum generality is desired.

So wouldn't that suggest that Collection should be used instead of List?

It depends on what you want to do. If you use a data structure
somewhere, you will know whether you want to allow duplicates or not,
and whether you want random access etc.

Collection OTOH is to be used as argument to functions which do not care
about that. Browse around in the Collection API, you’ll get a grasp of
it. E.g. addAll() takes a Collection as argument: the class on which it
is called will take care of the duplicates-or-not-issue, that does not
depend on which kind of collection is passed to the function.
sort() OTOH will take a List as argument since order is needed to be
able to talk about sorting.

So generally, you’ll do:

List<Whatever> myList = new ArrayList<Whatever>();
Collection<Something> = functionReturningCollection; // note that it
might actually return a Set or List, or some custom implementation
public usefulMethod(Collection<Stuff> args) {
// I just want some Stuff instances, don’t care which ones, since I
only use the enhanced for loop
}

etc.

HTH, H.
--
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.4-svn0 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

iD8DBQFHM0X2e+7xMGD3itQRAmEDAJ9avG2Mjr4arpYM4uLiqHakwLA/NACfQARF
th5EyGHFN1ZfQsf8G1LVnmQ=
=bv+v
-----END PGP SIGNATURE-----
 
P

Patricia Shanahan

Hendrik said:
Knute Johnson schreef:

It depends on what you want to do. If you use a data structure
somewhere, you will know whether you want to allow duplicates or not,
and whether you want random access etc.

Collection OTOH is to be used as argument to functions which do not care
about that. Browse around in the Collection API, you’ll get a grasp of
it. E.g. addAll() takes a Collection as argument: the class on which it
is called will take care of the duplicates-or-not-issue, that does not
depend on which kind of collection is passed to the function.
sort() OTOH will take a List as argument since order is needed to be
able to talk about sorting.

In many case, code that creates or modifies a structure needs to know if
it is supposed to be ordered, and how it handles duplicates. Code that
only needs to process each item in its natural order is more likely to
just see it as a Collection.

Patricia
 
L

Lew

Patricia said:
In many case, code that creates or modifies a structure needs to know if
it is supposed to be ordered, and how it handles duplicates. Code that
only needs to process each item in its natural order is more likely to
just see it as a Collection.

The rule is, "Use the most general type *applicable*."

Not, "Use the most general type."

If a Collection doesn't support what your algorithm needs, use the more
specific type that does, but nothing more specific than that.

So in Patricia's example, if the algorithm requires an ordered collection that
tolerates duplicates, use a List. A Collection will not have access to the
behaviors that you need. If the algorithm only requires that you iterate
through the collection, use Iterable; you don't even need a Collection.

So to Knute's question - that Collection is more general than List does not
automatically require the variable to be of type Collection. It is even valid
to declare a variable to be of a specific implementing class, if the full
behavior set of that class is what you need. This is the case, for example,
with java.util.Properties - it is really never used as a Map.
 
L

Lew

Knute said:
And one more question and I'll let this go back to where it was.

Is there any reason to do this for classes created on the stack?

Are you talking about anonymous and local classes? If not, what do you mean?

You have no choice but to declare anonymous classes as some more general type
by the very syntax of anonymous class declaration.

You wouldn't declare a local class unless you needed its specific behavior.
So while the rule could be said to apply ("Use the most general type
applicable"), the local class type is going to be the most general type
applicable.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top