Skip to main content

Proposal for Number sublcass API changes

12 replies [Last post]
darcy
Offline
Joined: 2003-06-15

Looking at bugs/enhancement #s: 4838318, 4951623, 4951621 (and others :-) I propose adding the following Constructors/methods to the Number subclasses to reduce the number of calls to toString (and thus reduce the amount of garbage generated).

I picked this tubset of the java API since it is fairly compact and stand alone (doing the whole java.* api would be huge!)

Good/bad idea? Comments?

Boolean.Boolean(CharSequence)
Boolean.parseBoolean(CharSequence)
Boolean.valueOf(CharSequence)

Byte.Byte(CharSequence)
Byte.decode(CharSequence)
Byte.valueOf(CharSequence, int)
Byte.valueOf(CharSequence)
Byte.parseByte(CharSequence, int)
Byte.parseByte(CharSequence)

Double.Double(CharSequence)
Double.valueOf(CharSequence)
Double.parseDouble(CharSequence)

Float.Float(CharSequence)
Float.valueOf(CharSequence)
Float.parseFloat(CharSequence)

Integer.Integer(CharSequence)
Integer.decode(CharSequence)
Integer.valueOf(CharSequence, int)
Integer.valueOf(CharSequence)
Integer.parseInt(CharSequence, int)
Integer.parseInt(CharSequence)

Long.Long(CharSequence)
Long.decode(CharSequence)
Long.valueOf(CharSequence, int)
Long.valueOf(CharSequence)
Long.parseLong(CharSequence)
Long.parseLong(CharSequence, int)

Short.Short(CharSequence)
Short.decode(CharSequence)
Short.valueOf(CharSequence)
Short.valueOf(CharSequence, int)
Short.parseShort(CharSequence, int)
Short.parseShort(CharSequence)

BigDecimal.BigDecimal(CharSequence, MathContext)
BigDecimal.BigDecimal(CharSequence)

BigInteger.BigInteger(CharSequence, int)
BigInteger.BigInteger(CharSequence)

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
darcy
Offline
Joined: 2003-06-15

"But your performance wouldn't change of course as you'd still be passing it Strings, so I don't see your point in wanting the feature in the first place."

(Keeping this one seperate since it is a different issue)

There is a performance difference. Right now you cannot pass a StringBuffer, StringBuilder, CharBuffer, etc... to those methods (and many many more in the java./javax. libraries). SO you have code like this:

StringBuilder builder;
int x;
...

// throwaway String created
x = Integer.parseInt(builder.toString());

Under the proposal you would have:

StringBuilder builder;
int x;
...

// no String created
x = Integer.parseInt(builder);

This speeds up code (in those cases) because:

1) there is no String created (see above where the person said ~20% of the time was spent constructing throw away Strings)

2) there is less garbage created, and thus less to clean up.

darcy
Offline
Joined: 2003-06-15

"REPLACING the methods taking a String with methods taking a CharSequence would prevent that bloat and probably not cause existing code to fail either."

You are correct that existing code that does not use reflection would not break by removing the String methods.

As has been pointed out, you cannot replace existing methods as it breaks refelction.

I thought a bit more on the ClassLoader idea... you could also do the same thing with reflection (@replaces and have the reflection mechanism add the method at runtime).

Either mechanism breaks tools that parse class files... but I don't see that as a huge problem as the @replaces annotation would ahve to be available at runtime.

The reflection mechanism might be a more viable change than the classloader change since it would break custom classloaders.

Is your objection based on the fact that it will increase the API or is it based on the fact that it will increase the downlaod size of the JDK/JRE?

mthornton
Offline
Joined: 2003-06-10

> The reflection mechanism might be a more viable
> change than the classloader change since it would
> break custom classloaders.
The change would be within the JVM defined implementation of ClassLoader.defineClass, so custom classloaders would not be affected.

> Is your objection based on the fact that it will
> increase the API
I think this is the main problem --- the change in the size of the JRE would be trivial.

darcy
Offline
Joined: 2003-06-15

"The change would be within the JVM defined implementation of ClassLoader.defineClass, so custom classloaders would not be affected."

Guess so :-)

It would probably make more sense to have it in the reflection code though, as it is only needed in the case of reflection and the code to create the methods could be done lazily, probably at the point of requesting a method via reflection. A (presumably small) performance decrease when getting the first method of a class (or getMethods/getDeclaredMethods) rather than a decrease on each and every class that gets loaded.

So the only time a penalty is paid is the first time reflection is used to get a method.

forax
Offline
Joined: 2004-10-07

> Sigh, more bloat.

Real story :)
This summer i've write with a friend
a parser of parser (like yacc) in java and
we try to minimise allocation.

To convert a sequence recognize by the lexer to
an int, we use Integer.parseInt(String).
So we need to create a String from the
char buffer (CharBuffer) in order to call parseInt.

Using a profiler, we found that 23% of the parsing
time was due to String creations.

So these methods could be very useful to
improved performance.

Rémi

darcy
Offline
Joined: 2003-06-15

Looking at Integer (and some of the other classes - so likely all of them) most of the methods become something like this:

Integer parseInt(String str)
{
return (parseInt((CharSequence)str);
}

Integer parseInt(CharSequence str)
{
// old code from Interger.parseInt
}

There are a few things in there like "startsWith" that use more than one character - and thus need to become calls to charAt (but that is probably offset by the removal of the Strings passed to startsWith).

I will take a stab at Integer to see what the diffs are and post it here in a bit (not going to gurantee it works - just a first stab at the implementation).

So the code bloat is minimal - essentially a number of new one-line methods. The API bloat is more but at the same time it is not a huge conceptual thing.

jwenting
Offline
Joined: 2003-12-02

now if you'd checked the API docs you'd have noticed that String already implements CharSequence so your methods specific for String would not be needed.
Adding them adds bloat, and unnecessary bloat at that.

REPLACING the methods taking a String with methods taking a CharSequence would prevent that bloat and probably not cause existing code to fail either.

But your performance wouldn't change of course as you'd still be passing it Strings, so I don't see your point in wanting the feature in the first place.

mthornton
Offline
Joined: 2003-06-10

Unfortunately replacing methods taking String with methods taking CharSequence would break existing compiled code. The method signature is determined at compile time. Hence backward compatibility requires that the String versions remain. Even recompiled code can be broken where reflection is used to look for say a constructor which takes a single String argument. It is a pity that Class.getConstructor and Class.getMethod require an exact signature match instead of using the same logic as the compiler does to find the most appropriate constructor/method.

It would be valuable if we could devise a scheme that would allow deprecated methods to be removed. Having a JVM rewrite 'old' classfiles on loading to replace references to old methods with new would be straight forward. However reflective access would remain a problem.

The proposer wants it because he has objects which already implement CharSequence and wants to use them directly without creating an intermediate String.

Message was edited by: mthornton

mthornton
Offline
Joined: 2003-06-10

How about encouraging people to use java.util.Scanner instead?

roscopeco
Offline
Joined: 2005-05-08

> How about encouraging people to use java.util.Scanner
> instead?

Second that, there's better ways to handle this already. Have you tried to find anything in javadoc lately?

jwenting
Offline
Joined: 2003-12-02

Sigh, more bloat.

darcy
Offline
Joined: 2003-06-15

Hmm... that got me thinking...

How about a new annotation like @replaces used like this:

@replaces(parseInt(java.lang.String)
public int parseInt(CharSeqaulce sequence)
{
...
}

Then remove the parseInt(String) method and have the class loader generate a new method for parseInt(String) that simply does:

public static int parseInt(String str)
{
return (parseInt((CharSeqence)str));
}

Then deprecated methods can be removed without breaking classes at runtime. The compiler would also need to do this (preferably with a flag to say don't do it so that it is easy to remove all uses of deprecated methods - errors are much harder to ignore than warnings :-).

This would allow for the replacement of methods without adding to the size of the jar files (could actually decrease them as more than one mathod may be able to be replaced) - only question is how much of an impact is there at runtime?

Time to write some code :-)