what is the RIGHT THING to make a constructor of a subclass, usingsuper()

M

Mark_Galeck

Hello, what is the RIGHT THING, to write a constructor for a
subclass, that needs to compute arguments to the super() call?? How
do experienced and elegant Java programmers do it?

The meaning of a subclass is that it adds more to its superclass, so
for example, it can have a constructor arguments types that the
superclass does not have. With these arguments, I have to first
compute the arguments to the superclass constructor (using the
arguments supplied to the subclass), and it is hard to do all these
computations inside the call to super(). I can do it, but it is, as
one of my first programming professors once put "your code is ugly and
miserable". Since Java is a well-designed language, I must be doing
the WRONG THING, what is it, how do I do it the right way??

Thank you for your insights

Mark
 
A

Arne Vajhøj

Mark_Galeck said:
Hello, what is the RIGHT THING, to write a constructor for a
subclass, that needs to compute arguments to the super() call?? How
do experienced and elegant Java programmers do it?

The meaning of a subclass is that it adds more to its superclass, so
for example, it can have a constructor arguments types that the
superclass does not have. With these arguments, I have to first
compute the arguments to the superclass constructor (using the
arguments supplied to the subclass), and it is hard to do all these
computations inside the call to super(). I can do it, but it is, as
one of my first programming professors once put "your code is ugly and
miserable". Since Java is a well-designed language, I must be doing
the WRONG THING, what is it, how do I do it the right way??

I think that the optimal solution is to redesign so that you
do not have that constructor complexity.

But if you do need it then the options are limited. I would
either go for inline calculation or if they become too long
use a static method in the sub class to do the calculations.

Arne
 
S

Stefan Ram

Mark_Galeck said:
and it is hard to do all these computations inside the call to super().

You can always use statements within an expression.

class Alpha
{ public Alpha( final int n )
{ java.lang.System.out.println( n ); } }

class Beta extends Alpha
{ public Beta()
{ super( new java.util.concurrent.Callable<java.lang.Integer>()
{ public java.lang.Integer call()
{ int i = 0;
i = i + 1;
i = i + 1;
i = i + 1;
i = i + 1;
return i; }}.call() ); }}

public class Main
{ public static void main( final java.lang.String[] args )
{ new Beta(); }}

4

Of course, you can also use a separate method for all these computations:

class Alpha
{ public Alpha( final int n )
{ java.lang.System.out.println( n ); } }

class Beta extends Alpha
{
public static int number()
{ int i = 0;
i = i + 1;
i = i + 1;
i = i + 1;
return i; }

public Beta(){ super( number() ); }}

public class Main
{ public static void main( final java.lang.String[] args )
{ new Beta(); }}

3

With regard to super, Java behaves like a pure functional language,
where only such nested calls are allowed (and no sequences of statements).
 
M

Mark_Galeck

Yes, thank you everybody, it seems like I did not realise you can call
a static method within a constructor, duh!

Also, just for reference to future newbies, a few days ago I posted a
similar gripe here, that there is no single event and handler that
JTextField text has changed. If you use DocumentEvent, you have to
implement insertUpdate and removeUpdate and changedUpdate, and anyway
that is probably not what one wants, since DocumentEvent happens on
editing every single character. Or you can use ActionEvent (which
gets fired on pressing Enter) and FocusEvent focusLost method, and
here you have to implement actionPeformed, focusLost, focusGained -
and also, the Enter and focusLost may have occured without any
change.


So, my solution was to implement my own subclass of JTextField, that
fires its own custom "TxtChangedEvent". This class catches its own
ActionEvent and focusEvents, processes them, and if a change of text
really occured, fires a single TxtChangedEvent, and it lets other
objects register to listen for those events - I also implemented the
interface TxtChangedListener. If you think it is worthwhile I can
post the code snippet here.

Mark
 
T

Tom Anderson

If you are left with that requirement as a necessary or desirable part
of the design, then the usual approach is probably to write a static
method in the class that you call as an argument to the call to super()
from your constructor. For example:

public class TestDerived extends TestBase
{
public TestDerived(int i)
{
super(intFromArg(i));
}

public static int intFromArg(int i) { return i; }
}

The static method can be as complicated as needed, leaving the call to
super() with just the method call rather than the actual computation.

That's what i would say is the Right Way to do it.

The problem comes when you have multiple arguments that need to be
computed together. For instance (and note that this isn't supposed to be
an example of good design!):

public class Customer {
public Customer(String firstName, String lastName) {
// do whatever
}
}

public class SlashSeparatedCustomer extends Customer {
public SlashSeparatedCustomer(String name) {
// THIS IS ILLEGAL!
int slash = name.indexOf('/') ;
String first = name.substring(0, slash) ;
String last = name.substring(slash + 1) ;
super(first, last) ;
}
}

The SlashSeparatedCustomer constructor as it is is illegal, but there's no
way to refactor it to use a static method, since you can't use a single
method call to fill in two arguments in a call. Well, you could do this:

public class SlashSeparatedCustomer extends Customer {
public SlashSeparatedCustomer(String name) {
super(splitName(name)[0], (splitName(name)[1]) ;
}
private static String[] splitName(String name) {
int slash = name.indexOf('/') ;
String first = name.substring(0, slash) ;
String last = name.substring(slash + 1) ;
return new String{} {first, last} ;
}
}

But that's grotesque.

In this case, what i would do is refactor the superclass constructor so
that it does its work by calling some method, let's call it init, and then
provide a protected no-args constructor:

public class Customer {
public Customer(String firstName, String lastName) {
init(firstName, lastName) ;
}
protected void init(String firstName, String lastName) {
// do whatever
}
protected Customer() {
// DOES NOT INITIALISE THE OBJECT!
}
}

Then you can write the subclass like this:

public class SlashSeparatedCustomer extends Customer {
public SlashSeparatedCustomer(String name) {
super() ; // could leave this implicit
int slash = name.indexOf('/') ;
String first = name.substring(0, slash) ;
String last = name.substring(slash + 1) ;
init(first, last) ;
}
}

The problem with this, of course, is that it means that Customer doesn't
guarantee that it always constructs itself properly, and thus if a
subclass gets it wrong and fails to call init, you have a broken instance.

You could have a flag, private boolean initialised, which is set to true
at the end of the init method, and which is checked by all the methods in
Customer, which throw something like UninitialisedInstanceException, a
RuntimeException, if they aren't initialised. You could also avoid the
need for an explicit flag by just checking that firstName is non-null or
something. However, i would say this is overkill - i'd just accept the
fact that Customer subclasses have to be careful when they use the no-op
constructor, and make sure my unit tests catch things like that.

I'm not really sure why java has the rule that the super call must be the
first thing in the constructor. I understand that you can't let a
constructor call instance methods, or access instance fields, until that's
been done, but why not let it call static methods, and methods of other
classes, and manipulate local variables? Basically, the rule would be that
you can't make explicit or implicit use of 'this' before the super call.
In that case, the first, currently illegal, version of the
SlashSeparatedCustomer constructor would be allowed, and thus life would
be a lot simpler.

tom
 
S

Stefan Ram

Tom Anderson said:
public class SlashSeparatedCustomer extends Customer {
public SlashSeparatedCustomer(String name) {
// THIS IS ILLEGAL!
int slash = name.indexOf('/') ;
String first = name.substring(0, slash) ;
String last = name.substring(slash + 1) ;
super(first, last) ;
}
}

Quite complicated, and still not perfect, because it
is not safe for multithreading or recursion (due to
the use of static fields):

class Customer
{ public Customer
( final java.lang.String first, final java.lang.String last )
{} }

class SlashSeparatedCustomer extends Customer
{
private static java.lang.String first;
private static java.lang.String first( final java.lang.String name )
{ if( !initialized )initialize( name ); return first; }

private static java.lang.String last;
private static java.lang.String last( final java.lang.String name )
{ if( !initialized )initialize( name ); return last; }

private static boolean initialized;
private static void initialize( final java.lang.String name )
{ if( !initialized )
{ final int slash = name.indexOf( '/' ) ;
first = name.substring( 0, slash );
last = name.substring( slash + 1 ); }}

public SlashSeparatedCustomer( final java.lang.String name )
{ super( first( name ), last( name )); }}
 
D

Daniele Futtorovic

If you are left with that requirement as a necessary or desirable part
of the design, then the usual approach is probably to write a static
method in the class that you call as an argument to the call to
super() from your constructor. For example:

public class TestDerived extends TestBase
{
public TestDerived(int i)
{
super(intFromArg(i));
}

public static int intFromArg(int i) { return i; }
}

The static method can be as complicated as needed, leaving the call to
super() with just the method call rather than the actual computation.

That's what i would say is the Right Way to do it.

The problem comes when you have multiple arguments that need to be
computed together. For instance (and note that this isn't supposed to be
an example of good design!):

public class Customer {
public Customer(String firstName, String lastName) {
// do whatever
}
}

public class SlashSeparatedCustomer extends Customer {
public SlashSeparatedCustomer(String name) {
// THIS IS ILLEGAL!
int slash = name.indexOf('/') ;
String first = name.substring(0, slash) ;
String last = name.substring(slash + 1) ;
super(first, last) ;
}
}

The SlashSeparatedCustomer constructor as it is is illegal, but there's
no way to refactor it to use a static method, since you can't use a
single method call to fill in two arguments in a call. Well, you could
do this:

public class SlashSeparatedCustomer extends Customer {
public SlashSeparatedCustomer(String name) {
super(splitName(name)[0], (splitName(name)[1]) ;
}
private static String[] splitName(String name) {
int slash = name.indexOf('/') ;
String first = name.substring(0, slash) ;
String last = name.substring(slash + 1) ;
return new String{} {first, last} ;
}
}

But that's grotesque.

In this case, what i would do is refactor the superclass constructor so
that it does its work by calling some method, let's call it init, and
then provide a protected no-args constructor:

public class Customer {
public Customer(String firstName, String lastName) {
init(firstName, lastName) ;
}
protected void init(String firstName, String lastName) {
// do whatever
}
protected Customer() {
// DOES NOT INITIALISE THE OBJECT!
}
}

Then you can write the subclass like this:

public class SlashSeparatedCustomer extends Customer {
public SlashSeparatedCustomer(String name) {
super() ; // could leave this implicit
int slash = name.indexOf('/') ;
String first = name.substring(0, slash) ;
String last = name.substring(slash + 1) ;
init(first, last) ;
}
}

The problem with this, of course, is that it means that Customer doesn't
guarantee that it always constructs itself properly, and thus if a
subclass gets it wrong and fails to call init, you have a broken instance.

You could have a flag, private boolean initialised, which is set to true
at the end of the init method, and which is checked by all the methods
in Customer, which throw something like UninitialisedInstanceException,
a RuntimeException, if they aren't initialised. You could also avoid the
need for an explicit flag by just checking that firstName is non-null or
something. However, i would say this is overkill - i'd just accept the
fact that Customer subclasses have to be careful when they use the no-op
constructor, and make sure my unit tests catch things like that.

I'm not really sure why java has the rule that the super call must be
the first thing in the constructor. I understand that you can't let a
constructor call instance methods, or access instance fields, until
that's been done, but why not let it call static methods, and methods of
other classes, and manipulate local variables? Basically, the rule would
be that you can't make explicit or implicit use of 'this' before the
super call. In that case, the first, currently illegal, version of the
SlashSeparatedCustomer constructor would be allowed, and thus life would
be a lot simpler.

In such cases you'd use the factory pattern.
 
T

Tom Anderson

Quite complicated, and still not perfect, because it
is not safe for multithreading or recursion (due to
the use of static fields):

class Customer
{ public Customer
( final java.lang.String first, final java.lang.String last )
{} }

class SlashSeparatedCustomer extends Customer
{
private static java.lang.String first;
private static java.lang.String first( final java.lang.String name )
{ if( !initialized )initialize( name ); return first; }

private static java.lang.String last;
private static java.lang.String last( final java.lang.String name )
{ if( !initialized )initialize( name ); return last; }

private static boolean initialized;
private static void initialize( final java.lang.String name )
{ if( !initialized )
{ final int slash = name.indexOf( '/' ) ;
first = name.substring( 0, slash );
last = name.substring( slash + 1 ); }}

public SlashSeparatedCustomer( final java.lang.String name )
{ super( first( name ), last( name )); }}

Yep, that's pretty evil too.

You could make it threadsafe by using a
java.util.concurrent.locks.ReentrantLock, which you would acquire in
initialize, and then release after the super call. You could also clear
the cache variables there too. Like this:

private static final Lock initLock = new ReentrantLock() ;

private static void initialize(String name) {
if (!initialized) {
initLock.lock() ;
int slash = name.indexOf( '/' ) ;
first = name.substring( 0, slash );
last = name.substring( slash + 1 );
}
}

public SlashSeparatedCustomer(String name) {
super(first(name), last(name)) ;
postinitialize() ;
}

private void postinitialize() {
first = null ;
last = null ;
initLock.unlock() ;
}

Making it recursable would be harder. You could factor the cache variables
into a class, say CustomerParameters, and maintain a stack of them, so
that if initialize was called a second time (detected by the lock being
acquired but the cache fields already being set), you push the current
cache values onto the stack and carry on; you would then pop the stack in
postinitialize.

Although at that point, the Right Solution here becomes clear: you define
the CustomerParameters class in Customer (as a protected static class, i
think - is that even possible?), then give Customer a constructor which
takes one, and uses it to set its fields. You can then put all your
complex before-super logic in a static method which returns a
CustomerParameters object:

class Customer {
protected static class Parameters {
public final String firstName ;
public final String lastName ;
public Parameters(String firstName, String lastName) {
this.firstName = firstName ;
this.lastName = lastName ;
}
}

private final String firstName ;
private final String lastName ;
public Customer(String firstName, String lastName) {
this.firstName = firstName ;
this.lastName = lastName ;
}
protected Customer(Parameters params) {
this(params.firstName, params.lastName) ;
}
}

class SlashSeparatedCustomer extends Customer {
private static Customer.Parameters parse(String name) {
int slash = name.indexOf('/') ;
String first = name.substring(0, slash) ;
String last = name.substring(slash + 1) ;
return new Customer.Params(first, last) ;
}

public SlashSeparatedCustomer(String name) {
super(parse(name)) ;
}
}

The underlying trick here is binding together all the things you want in
an object, and then - and this is really the heart of it - using a method
call to effectively assign that to a local variable, from which you can
then read out fields. The second call creates a method parameter, which is
basically like a local variable, and it does it in a situation where
creating local variables isn't allowed. Does that make sense?

And in fact, once you see it like that, you can push this trick down
entirely to the subclass level (and simplify a bit):

class Customer {
private final String firstName ;
private final String lastName ;
public Customer(String firstName, String lastName) {
this.firstName = firstName ;
this.lastName = lastName ;
}
}

class SlashSeparatedCustomer extends Customer {
private static class Parameters {
public final String firstName ;
public final String lastName ;
public Parameters(String name) {
int slash = name.indexOf('/') ;
firstName = name.substring(0, slash) ;
lastName = name.substring(slash + 1) ;
}
}

private SlashSeparatedCustomer(Parameters params) {
super(params.firstName, params.lastName) ;
}
public SlashSeparatedCustomer(String name) {
this(new Parameters(name)) ;
}
}

Maybe even better:

class SlashSeparatedCustomer extends Customer {
private static String[] parse(String name) {
int slash = name.indexOf('/') ;
firstName = name.substring(0, slash) ;
lastName = name.substring(slash + 1) ;
return new String[] {firstName, lastName} ;
}

private SlashSeparatedCustomer(String[] params) {
super(params[0], params[1]) ;
}
public SlashSeparatedCustomer(String name) {
this(parse(name)) ;
}
}

Yes, this uses an array to hold multiple return values, which is a bit
icky, and won't work if the parameters are of different types (at least,
not without casts, and then it's *really* icky), but it saves having to
create a class just for this workaround.

And that is my final word on the matter.

For today.

tom
 
T

Tom Anderson

On Sun, 27 Jul 2008 18:17:04 -0700, Mark_Galeck

Hello, what is the RIGHT THING, to write a constructor for a
subclass, that needs to compute arguments to the super() call?? How
do experienced and elegant Java programmers do it?

If you are left with that requirement as a necessary or desirable part of
the design, then the usual approach is probably to write a static method
in the class that you call as an argument to the call to super() from your
constructor. For example:

public class TestDerived extends TestBase
{
public TestDerived(int i)
{
super(intFromArg(i));
}

public static int intFromArg(int i) { return i; }
}

The static method can be as complicated as needed, leaving the call to
super() with just the method call rather than the actual computation.

That's what i would say is the Right Way to do it.

The problem comes when you have multiple arguments that need to be computed
together. For instance (and note that this isn't supposed to be an example
of good design!):

public class Customer {
public Customer(String firstName, String lastName) {
// do whatever
}
}

public class SlashSeparatedCustomer extends Customer {
public SlashSeparatedCustomer(String name) {
// THIS IS ILLEGAL!
int slash = name.indexOf('/') ;
String first = name.substring(0, slash) ;
String last = name.substring(slash + 1) ;
super(first, last) ;
}
}

The SlashSeparatedCustomer constructor as it is is illegal, but there's no
way to refactor it to use a static method, since you can't use a single
method call to fill in two arguments in a call. Well, you could do this:

public class SlashSeparatedCustomer extends Customer {
public SlashSeparatedCustomer(String name) {
super(splitName(name)[0], (splitName(name)[1]) ;
}
private static String[] splitName(String name) {
int slash = name.indexOf('/') ;
String first = name.substring(0, slash) ;
String last = name.substring(slash + 1) ;
return new String{} {first, last} ;
}
}

But that's grotesque.

In this case, what i would do is refactor the superclass constructor so
that it does its work by calling some method, let's call it init, and then
provide a protected no-args constructor:

public class Customer {
public Customer(String firstName, String lastName) {
init(firstName, lastName) ;
}
protected void init(String firstName, String lastName) {
// do whatever
}
protected Customer() {
// DOES NOT INITIALISE THE OBJECT!
}
}

Then you can write the subclass like this:

public class SlashSeparatedCustomer extends Customer {
public SlashSeparatedCustomer(String name) {
super() ; // could leave this implicit
int slash = name.indexOf('/') ;
String first = name.substring(0, slash) ;
String last = name.substring(slash + 1) ;
init(first, last) ;
}
}

The problem with this, of course, is that it means that Customer doesn't
guarantee that it always constructs itself properly, and thus if a subclass
gets it wrong and fails to call init, you have a broken instance.

You could have a flag, private boolean initialised, which is set to true at
the end of the init method, and which is checked by all the methods in
Customer, which throw something like UninitialisedInstanceException, a
RuntimeException, if they aren't initialised. You could also avoid the need
for an explicit flag by just checking that firstName is non-null or
something. However, i would say this is overkill - i'd just accept the fact
that Customer subclasses have to be careful when they use the no-op
constructor, and make sure my unit tests catch things like that.

I'm not really sure why java has the rule that the super call must be the
first thing in the constructor. I understand that you can't let a
constructor call instance methods, or access instance fields, until that's
been done, but why not let it call static methods, and methods of other
classes, and manipulate local variables? Basically, the rule would be that
you can't make explicit or implicit use of 'this' before the super call. In
that case, the first, currently illegal, version of the
SlashSeparatedCustomer constructor would be allowed, and thus life would be
a lot simpler.

In such cases you'd use the factory pattern.

Yes!

tom
 
D

Daniel Pitts

Mark_Galeck said:
Hello, what is the RIGHT THING, to write a constructor for a
subclass, that needs to compute arguments to the super() call?? How
do experienced and elegant Java programmers do it?

The meaning of a subclass is that it adds more to its superclass, so
for example, it can have a constructor arguments types that the
superclass does not have. With these arguments, I have to first
compute the arguments to the superclass constructor (using the
arguments supplied to the subclass), and it is hard to do all these
computations inside the call to super(). I can do it, but it is, as
one of my first programming professors once put "your code is ugly and
miserable". Since Java is a well-designed language, I must be doing
the WRONG THING, what is it, how do I do it the right way??

Thank you for your insights

Mark
Perhaps the problem is that you're trying to use inheritance of
implementation when you should be using composition or some other design
altogether.

If you really want your "subclass" to have the same interface (and be
polymorphic), then you should consider creating an interface for it.

That way, the "super(...)" call actually becomes a "new Delegate(...)"
call instead, and can occur anywhere in the constructor.

Hope this helps,
Daniel.
 
D

Daniel Pitts

Tom said:
If you are left with that requirement as a necessary or desirable part
of the design, then the usual approach is probably to write a static
method in the class that you call as an argument to the call to
super() from your constructor. For example:

public class TestDerived extends TestBase
{
public TestDerived(int i)
{
super(intFromArg(i));
}

public static int intFromArg(int i) { return i; }
}

The static method can be as complicated as needed, leaving the call to
super() with just the method call rather than the actual computation.

That's what i would say is the Right Way to do it.

The problem comes when you have multiple arguments that need to be
computed together. For instance (and note that this isn't supposed to be
an example of good design!):

public class Customer {
public Customer(String firstName, String lastName) {
// do whatever
}
}

public class SlashSeparatedCustomer extends Customer {
public SlashSeparatedCustomer(String name) {
// THIS IS ILLEGAL!
int slash = name.indexOf('/') ;
String first = name.substring(0, slash) ;
String last = name.substring(slash + 1) ;
super(first, last) ;
}
}

The SlashSeparatedCustomer constructor as it is is illegal, but there's
no way to refactor it to use a static method, since you can't use a
single method call to fill in two arguments in a call. Well, you could
do this:

public class SlashSeparatedCustomer extends Customer {
public SlashSeparatedCustomer(String name) {
super(splitName(name)[0], (splitName(name)[1]) ;
}
private static String[] splitName(String name) {
int slash = name.indexOf('/') ;
String first = name.substring(0, slash) ;
String last = name.substring(slash + 1) ;
return new String{} {first, last} ;
}
}

But that's grotesque.
Yes it is, why not use:
public class SlashSeparatedCustomer extends Customer {
public SlashSeparatedCustomer(String name) {
super(firstName(name), (lastName(name)) ;
}
private static String firstName(String name) {
return name.substring(0, name.indexOf('/')) ;
}
private static String lastName(String name) {
return name.substring(name.indexOf('/')+1) ;
}
}

Actually, why is this a separate class at all? It just takes a different
argument type for the constructor, sounds like a static factory method
is what you want.
In this case, what i would do is refactor the superclass constructor so
that it does its work by calling some method, let's call it init, and
then provide a protected no-args constructor:

public class Customer {
public Customer(String firstName, String lastName) {
init(firstName, lastName) ;
}
protected void init(String firstName, String lastName) {
// do whatever
}
protected Customer() {
// DOES NOT INITIALISE THE OBJECT!
}
}

Then you can write the subclass like this:

public class SlashSeparatedCustomer extends Customer {
public SlashSeparatedCustomer(String name) {
super() ; // could leave this implicit
int slash = name.indexOf('/') ;
String first = name.substring(0, slash) ;
String last = name.substring(slash + 1) ;
init(first, last) ;
}
}

The problem with this, of course, is that it means that Customer doesn't
guarantee that it always constructs itself properly, and thus if a
subclass gets it wrong and fails to call init, you have a broken instance.
This is a bad design for many reasons, including the fact that you're
calling a non-final/non-private member method from the constructor.
You could have a flag, private boolean initialised, [snip]
whoah whoah whoah! Don't try to handle initialization after the fact.
I'm not really sure why java has the rule that the super call must be
the first thing in the constructor.
Because Java guarantees that the super class is fully constructed before
the construction of the derived class begins.
I understand that you can't let a
constructor call instance methods, or access instance fields, until
that's been done, but why not let it call static methods, and methods of
other classes, and manipulate local variables? Basically, the rule would
be that you can't make explicit or implicit use of 'this' before the
super call. In that case, the first, currently illegal, version of the
SlashSeparatedCustomer constructor would be allowed, and thus life would
be a lot simpler.

tom

It sounds like you're trying to create a new class that simply handles
initialization differently than the base class. if that is ALL you are
doing, then consider using a factory method instead:

public class Customer {
public static Customer fromSlashSeparatedName(String name) {
int slash = name.indexOf('/') ;
String first = name.substring(0, slash) ;
String last = name.substring(slash + 1) ;
return new Customer(first, last);
}
//... rest of Customer class
}

If you *really* do need implementation *and* interface inheritance, then
still consider using a factory method.
 
R

RedGrittyBrick

Lew said:
Josh Bloch has an entire item in /Effective Java/ recommending the use
of a factory over constructors by preference most of the time. His
reasoning is a more fleshed-out version of these points.

The book is a necessity for anyone wishing to be a Java programmer.

The second edition arrived on my doorstep a couple of days ago, I find
it provides very clear explanations for it's recommendations with
examples that illustrate the pros and cons.

My expectations were high after the way it has been enthused over in
this forum. So far it has exceeded my expectations.

I wouldn't advocate it as the first book to buy when learning java
(maybe O'Reilly's "Learning Java" is that) but I'd recommend it as a
second book to be bought quite soon after picking up the basics of Java.
 
M

Mark Space

RedGrittyBrick said:
I wouldn't advocate it as the first book to buy when learning java
(maybe O'Reilly's "Learning Java" is that) but I'd recommend it as a
second book to be bought quite soon after picking up the basics of Java.

I totally agree with this. _Effective Java_ is a very approachable
book. Getting it early in one's learning career is a good thing. As
soon as you get through generics in _Learning Java_ or the equivalent in
some other book, you can start looking for additional material. Once
you have the basics of the language (syntax, semantics) under your belt,
you can start challenging yourself with more material.
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top