Question about Generics

R

Rhino

I am currrently trying to "genericize" some of my older classes but I'm
having trouble with this simple class:

================================================================
public class IntRange extends TreeSet {

public IntRange(int firstInt, int secondInt) {

add(new Integer(firstInt));
add(new Integer(secondInt));
}

public IntRange(int[] intRange) {

if (intRange.length != 2) {
throw new IllegalArgumentException("The IntRange array must have
exactly two values.");
}

add(new Integer(intRange[0]));
add(new Integer(intRange[1]));
}


public boolean between(int input) {

if (input >= ((Integer) first()).intValue() && input <= ((Integer)
last()).intValue())
return (true);
else
return (false);
}

public int[] getValues() {

int[] values = new int[2];
values[0] = ((Integer) first()).intValue();
values[1] = ((Integer) last()).intValue();

return values;
}
}
================================================================

Can anyone tell me how to change the add() lines in the constructors to make
the compiler accept them? I thought that changing "public class IntRange
extends TreeSet" to "public class IntRange <Integer> extends TreeSet" might
solve all of my compiler warnings but it didn't; I'm not sure why. Could
someone explain what I _should_ do?

Frankly, I found the article on generics in the API pretty unhelpful in
getting beyond the most basic ideas. Can anyone point me to an article or
tutorial that explains these things more clearly? Then maybe I can
"genericize" the rest of my code on my own....
 
T

Torkel Franzen

Rhino said:
Can anyone tell me how to change the add() lines in the constructors to make
the compiler accept them? I thought that changing "public class IntRange
extends TreeSet" to "public class IntRange <Integer> extends TreeSet" might
solve all of my compiler warnings but it didn't; I'm not sure why.

The other way around. Change

public class IntRange extends TreeSet {

to

public class IntRange extends TreeSet<Integer>{
 
R

Rhino

Torkel Franzen said:
The other way around. Change

public class IntRange extends TreeSet {

to

public class IntRange extends TreeSet<Integer>{

Yes, of course, that's it. I figured this out just after I posted but hadn't
managed to get back in time to mention that.

But if anyone can still point me to a clearer explanation of generics than
the one in the API, I'd love to hear about it :) I feel sure that other,
harder, problems will come to light as I try to make older code use
generics.

Rhino
 
M

Mike Schilling

But if anyone can still point me to a clearer explanation of generics than
the one in the API, I'd love to hear about it :) I feel sure that other,
harder, problems will come to light as I try to make older code use
generics.

Not the JLS :)

Seriously, which in previous editions I've gone to the JLS for the
definitive answer to thorny questions, JLS 3 is crap. Even many of the
examples are wrong.
 
T

Torkel Franzen

Mike Schilling said:
Seriously, which in previous editions I've gone to the JLS for the
definitive answer to thorny questions, JLS 3 is crap.

No, no, it's great stuff.
 
R

Rhino

Thomas Hawtin said:
Rhino said:
public class IntRange extends TreeSet {

As mentioned in another reply, that should be:

public class IntRange extends TreeSet<Integer> {

This is a really odd class. It sounds like a range of int (with inclusive
values by the looks of the code, which is sensible as you can't have one
more than Integer.MAX_VALUE in int).
public IntRange(int firstInt, int secondInt) {

Not very descriptive parameters.
add(new Integer(firstInt));
add(new Integer(secondInt));

Can be written as:

add(firstInt);
add(secondInt);

If you didn't want to use autoboxing, you can do it slightly better as:

add(Integer.valueOf(firstInt));
add(Integer.valueOf(secondInt));

public boolean between(int input) {

Again you could go for a better method name.
if (input >= ((Integer) first()).intValue() && input <=
((Integer) last()).intValue())
return (true);
else
return (false);

This can be better written as:

return first() <= input && input <= last();
int[] values = new int[2];
values[0] = ((Integer) first()).intValue();
values[1] = ((Integer) last()).intValue();

return values;

Again, that can be written:

return new int[] { first(), last() };

Either of the above could throw a peculiar exception if the set is empty.
That class is trying to capture a range of ints so that there is a way of
saying that some third int is or is not within the range depicted by the
IntRange. For instance, if I say that the IntRange consists of a low value
of 3 and a high value of 9, I want to be able to say that the number 23 is
not between the values in the set while 7 is.

I probably haven't done it as well as it could be done; it was really just
an early attempt in an old project that I've put to the side for a while.
Thanks for your suggestions on improving it; if you have more, please go
ahead.

I'm not sure how I could ever have that IntRange be empty to cause me
problems: both constructors insist on exactly two values. Is there some way
to instantiate the IntRange that I haven't thought of which might cause an
empty set?

Rhino
 
T

Thomas Hawtin

Rhino said:
public class IntRange extends TreeSet {

As mentioned in another reply, that should be:

public class IntRange extends TreeSet<Integer> {

This is a really odd class. It sounds like a range of int (with
inclusive values by the looks of the code, which is sensible as you
can't have one more than Integer.MAX_VALUE in int).
public IntRange(int firstInt, int secondInt) {

Not very descriptive parameters.
add(new Integer(firstInt));
add(new Integer(secondInt));

Can be written as:

add(firstInt);
add(secondInt);

If you didn't want to use autoboxing, you can do it slightly better as:

add(Integer.valueOf(firstInt));
add(Integer.valueOf(secondInt));

public boolean between(int input) {

Again you could go for a better method name.
if (input >= ((Integer) first()).intValue() && input <= ((Integer)
last()).intValue())
return (true);
else
return (false);

This can be better written as:

return first() <= input && input <= last();
int[] values = new int[2];
values[0] = ((Integer) first()).intValue();
values[1] = ((Integer) last()).intValue();

return values;

Again, that can be written:

return new int[] { first(), last() };

Either of the above could throw a peculiar exception if the set is empty.

Tom Hawtin
 
T

Torkel Franzen

Mike Schilling said:
Sorry, I can't tell if you'e joking or being serious. If the latter, can
you tell me why you say that?

Well, it is the ultimate fountain of wisdom, and quite readable. Can
you give a couple of examples of thorny questions where it let you
down?
 
T

Thomas Hawtin

Rhino said:
I'm not sure how I could ever have that IntRange be empty to cause me
problems: both constructors insist on exactly two values. Is there some way
to instantiate the IntRange that I haven't thought of which might cause an
empty set?

You could have:

IntRange range = new IntRange(42, 0);
range.clear();
System.err.println(range.between(3));

If you want IntRange to support SortedSet<Integer> extend
AbstractSet<Integer> and provide the missing methods as needed. A lot of
the methods should throw UnsupportedOperationException.

Tom Hawtin
 
R

Rhino

Thomas Hawtin said:
You could have:

IntRange range = new IntRange(42, 0);
range.clear();
System.err.println(range.between(3));
Ahh, I see....

Hmm, maybe I should override the clear() method and make the override empty
to prevent that. Or would it be better to make the implementation throw
UnsupportedOperationException? Yes, the latter makes more sense, otherwise a
user might not realize that clear() is not doing anything by design and that
it isn't broken.
If you want IntRange to support SortedSet<Integer> extend
AbstractSet<Integer> and provide the missing methods as needed. A lot of
the methods should throw UnsupportedOperationException.
Yes, I see your point. Thanks for the suggestions!

Rhino
 
R

Robert M. Gary

I will be interested in hearing how this works out for you. I've mostly
given up on "Generics" (we call them "Templates" in C++). The problem
with Generics is that without a "typedef" type ability you end up with
classes who's names can often wrap around your screen. Define an
Iterator for one and I've actually had cases where the class name
itself was two lines long. C++ solved this with typedef, allowing you
to rename the big long ugly class name to something reasonable.

-Robert
 
M

Mike Schilling

Torkel Franzen said:
Well, it is the ultimate fountain of wisdom, and quite readable. Can
you give a couple of examples of thorny questions where it let you
down?

If my copy were in front of me, I would give chapter and verse. In
general, generics, and in particular, many of the examples that were new for
JLS 3 do not compile.
 
S

Stefan Ram

Rhino said:
That class is trying to capture a range of ints so that there
is a way of saying that some third int is or is not within the
range depicted by the IntRange.

This is somewhat similar to:

http://download.java.net/jdk6/docs/api/javax/swing/DefaultBoundedRangeModel.html

Here is a simple implementation:

class Range
{ final int min; final int max;
public void Range( final int min, final int max )
{ this.min = min; this.max = max; }
public bool contains( final int value )
{ return value >= min && value <= max; }}

I see no reason to use TreeSets, arrays or Integer objects.
 
E

Eric Sosman

Rhino wrote On 01/18/06 17:34,:
Ahh, I see....

Hmm, maybe I should override the clear() method and make the override empty
to prevent that. Or would it be better to make the implementation throw
UnsupportedOperationException? Yes, the latter makes more sense, otherwise a
user might not realize that clear() is not doing anything by design and that
it isn't broken.

I'd take yet another step back and ask why you've
decided to make IntRange extend TreeSet. The inherited
methods are potential sources of trouble, since the
caller can use them to modify the TreeSet without the
IntRange's knowledge. And there's nothing in what you've
shown us of IntRange that appears to need TreeSet's
machinery. Why not just a free-standing IntRange that
holds two values?

public class IntRange {
private final int low, high;
public IntRange(int low, int high) {
this.low = Math.min(low, high);
this.high = Math.max(low, high);
}
public IntRange(int[] range) {
this(range[0], range[1]);
}
public boolean isInRange(int value) {
return low <= value && value <= high;
}
public int[] getValues() {
int[] values = { low, high };
return values;
}
}

Unless there's more to IntRange than you've revealed, I'd
recommend following the KISS ("Keep It Simple, Stupid!")
principle.
 
T

Tony Morris

Mike Schilling said:
If my copy were in front of me, I would give chapter and verse. In
general, generics, and in particular, many of the examples that were new for
JLS 3 do not compile.

That's because at one stage they did compile, only the JSR "expert" groups
found that they had to change the definition of 'generics' in order to
appear less contrived - and without telling anyone (including themselves).
Welcome to corporate software.

--
Tony Morris
http://tmorris.net/

Java Questions and Answers
http://jqa.tmorris.net/
 
I

Ian Pilcher

Eric said:
Unless there's more to IntRange than you've revealed, I'd
recommend following the KISS ("Keep It Simple, Stupid!")
principle.

Presumably, the OP wants his IntRange to behave like a Set<Integer>,
with contains, containsAll, iterator, etc.

If this is the case, extending AbstractSet (or possibly AbstractList) is
probably the way to go.
 
S

Stefan Ram

Rhino said:
That class is trying to capture a range of ints so that there
is a way of saying that some third int is or is not within the
range depicted by the IntRange.

This is somewhat similar to:

http://download.java.net/jdk6/docs/api/javax/swing/DefaultBoundedRangeModel.html

Here is a simple implementation:

class Range
{ final int min; final int max;
public Range( final int min, final int max )
{ this.min = min; this.max = max; }
public boolean contains( final int value )
{ return value >= min && value <= max; }}

I see no reason to use TreeSets, arrays or Integer objects.
 

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

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,071
Latest member
MetabolicSolutionsKeto

Latest Threads

Top