Java Forum / General / July 2006
Converting char(s) into String
ponga - 08 Jun 2006 19:08 GMT I spent hours trying to figure this out, so for others benifit, here it is:
I had a problem trying to concatenate a few characters into a String. This was what I was trying to do, with no success: String s1 = "Some text"; String str = s1.charAt(0) + s1.charAt(5); Oddly enough, Eclipse threw a "Type mismatch: cannot convert from int to String" int?? Anyway, I battled this for a few hours and here is what works: String str = "" + s1.charAt(0) + s1.charAt(5);
WTF? Anyway, there you have it. -Mike
John O'Conner - 08 Jun 2006 19:14 GMT > I spent hours trying to figure this out, so for others benifit, here it > is: [quoted text clipped - 7 lines] > int?? Anyway, I battled this for a few hours and here is what works: > String str = "" + s1.charAt(0) + s1.charAt(5); s1.charAt(0) returns a char, s1.charAt(5) returns a char. Now you try to add them, and the chars turn into int types for that process. The result is an int. Then you try to assign into str, which is String type. Note: the '+' operator is only overloaded for String concatenation, not char concatenation to produce strings.
Voila! a type mismatch.
Maybe a less confusing way to do this is this:
StringBuffer strBuf = new StringBuffer(); strBuff.append(s1.charAt(0)); strBuff.append(s1.charAt(5));
-- John O'Conner
Thomas Hawtin - 08 Jun 2006 19:40 GMT >> String str = "" + s1.charAt(0) + s1.charAt(5);
> Maybe a less confusing way to do this is this: > > StringBuffer strBuf = new StringBuffer(); > strBuff.append(s1.charAt(0)); > strBuff.append(s1.charAt(5)); String str = strBuff.toString();
One thing to be aware of is that passing a char to the constructor does not do what you may expect.
String str = new StringBuilder(s1.charAt(0)).append(s2.charAt(5)).toString();
You don't need to go through StringBuffer (or better StringBuilder) for something this simple.
String str = String.valueOf(new char[] { s1.charAt(0), s1.charAt(5) });
Tom Hawtin
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
amitdev@gmail.com - 09 Jun 2006 00:15 GMT > >> String str = "" + s1.charAt(0) + s1.charAt(5); > [quoted text clipped - 10 lines] > String str = > new StringBuilder(s1.charAt(0)).append(s2.charAt(5)).toString(); This will create a StringBuilder of size : (int)(s1.charAt(0)). Probably not what you want. The right way is: new StringBuilder().append(s1.charAt(0)).append(s2.charAt(5)).toString();
> You don't need to go through StringBuffer (or better StringBuilder) for > something this simple. > > String str = String.valueOf(new char[] { s1.charAt(0), s1.charAt(5) }); How about: String str = new String(new char[] { s1.charAt(0), s1.charAt(5) });
> Tom Hawtin > -- > Unemployed English Java programmer > http://jroller.com/page/tackline/ Thomas Hawtin - 09 Jun 2006 16:22 GMT >> String str = String.valueOf(new char[] { s1.charAt(0), s1.charAt(5) }); >> > How about: > String str = new String(new char[] { s1.charAt(0), s1.charAt(5) }); I don't care whether I get a new string or a reused one. In my opinion, it's better to give the library class the extra freedom.
I would go so far as to say that immutable classes should, in general, not have public constructors.
Tom Hawtin
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
Mike Schilling - 09 Jun 2006 01:33 GMT >I spent hours trying to figure this out, so for others benifit, here it > is: [quoted text clipped - 9 lines] > > WTF? char is actually an integral type, so, for instance
'a' + 'b'
adds the unicode values for 'a' and 'b' and results in an int. However, for all types,
String + anytype
converts the anytype to a String value and concatenates the two. Thus your solution
"" + 'a' + 'b'
is effectively the same as
"" + "a" + "b"
that is, "ab".
You could also use the String constructor:
new String(new char[] { 'a', 'b'})
There are no other ways to perform this conversion directly [1]. (String)char seems logical, but isn't allowed.
1. That occur to me at the moment, anyway.
Chris Uppal - 09 Jun 2006 10:29 GMT > There are no other ways to perform this conversion directly [1]. > (String)char seems logical, but isn't allowed. One could write a utility function or two; something like (untested):
class StringUtils { public static String concatenate(Object... args) { StringBuilder builder = new StringBuilder(); for (Object arg : args) builder.append(arg); return builder.toString(); }
public static String concatenateWithSeparator(Object separator, Object... args) { StringBuilder builder = new StringBuilder(); for (Object arg : args) { if (builder.length() > 0) builder.append(separator); builder.append(arg); } return builder.toString(); } }
(It would be nice if we were allowed to use ... for arguments before the last one -- this isn't C, there's no technical reason why the compiler couldn't sort it out.)
-- chris
Dimitri Maziuk - 09 Jun 2006 17:45 GMT Mike Schilling sez:
>>I spent hours trying to figure this out, so for others benifit, here it >> is: [quoted text clipped - 38 lines] > > 1. That occur to me at the moment, anyway. s1.substring( 0, 1 ) + s1.substring( 5, 6 )
A dumb compiler would presumably create 3.1 transient strings for "" + s.charAt( i ) + s.charAt( j ) (.1 because "" would be interned and created at startup).
s.substring( i, i+1 ) + s.substring( j, j+1 ) would only create 2 transients.
Rumour has it, a smart compiler can optimize transients away, the question is how smart is "smart". My guess would be that it will work for .substring() version and likely won't work for .charAt() version (unless the optimizer can look past the return value of charAt() and notice we're actually pulling out substrings).
The bulletproof way is, of course, appending to StringBuilder as suggested upthread: you get a single transient (and much "lighter") buffer instead of 2+ transient strings.
Dima
 Signature Politics and religion are just like software and hardware. They all suck, the documentation is provably incorrect, and all the vendors tell lies. -- Andrew Dalgleish
Thomas Hawtin - 09 Jun 2006 18:45 GMT > s1.substring( 0, 1 ) + s1.substring( 5, 6 ) > [quoted text clipped - 5 lines] > s.substring( i, i+1 ) + s.substring( j, j+1 ) > would only create 2 transients. It's worse than that, there are StringBuilders about. I have no idea why javac produces such bad code, but that is what it does. See below.
For a more reasonable use of substring, use String.concat rather than letting the compiler louse it up:
str.substring(i, i+1).concat(str.substring(j, j+1))
That, I believe, only produces two temporary String objects (but no extra char[]s). String.valuOf(char[]) just creates one temporary char[]. StringBuilder will create a temporary StringBuilder object and an oversized (a little) char[].
> Rumour has it, a smart compiler can optimize transients away, > the question is how smart is "smart". My guess would be that > it will work for .substring() version and likely won't work > for .charAt() version (unless the optimizer can look past the > return value of charAt() and notice we're actually pulling out > substrings). It looks as if one of the Sun 1.6 fcs byte -> machine code compilers will be able to do the analysis (at least if you use -XX:+DoEscapeAnalysis) but does not do stack allocation.
However, allocating short lived objects is surprisingly cheap.
> The bulletproof way is, of course, appending to StringBuilder > as suggested upthread: you get a single transient (and much > "lighter") buffer instead of 2+ transient strings. Strings will share the char[]. So it's creating a StringBuilder plus char[] vs two Strings (and *no* temporary char[]s).
Of course, it all depends upon the implementation used.
Tom Hawtin
class X { String fn(String str, int i, int j) { return str.substring(i, i+1) + str.substring(j, j+1); } }
$ javap -c X Compiled from "X.java" class X extends java.lang.Object{ X(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return
java.lang.String fn(java.lang.String, int, int); Code: 0: new #2; //class java/lang/StringBuilder 3: dup 4: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V 7: aload_1 8: iload_2 9: iload_2 10: iconst_1 11: iadd 12: invokevirtual #4; //Method java/lang/String.substring:(II)Ljava/lang/String; 15: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 18: aload_1 19: iload_3 20: iload_3 21: iconst_1 22: iadd 23: invokevirtual #4; //Method java/lang/String.substring:(II)Ljava/lang/String; 26: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 29: invokevirtual #6; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 32: areturn
}
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
Jussi Piitulainen - 09 Jun 2006 20:01 GMT > A dumb compiler would presumably create 3.1 transient strings > for [quoted text clipped - 3 lines] > s.substring( i, i+1 ) + s.substring( j, j+1 ) > would only create 2 transients. I thought the first one was specified to be equivalent to
new StringBuffer() .append("") .append(s.charAt(i)) .append(s.charAt(j)) .toString(),
or maybe it's a StringBuilder nowadays. Why would even a dumb compiler produce worse code?
Oliver Wong - 09 Jun 2006 21:12 GMT >> A dumb compiler would presumably create 3.1 transient strings >> for [quoted text clipped - 14 lines] > or maybe it's a StringBuilder nowadays. Why would even a dumb compiler > produce worse code? Perhaps because it depends on knowledge of the API. It might be occasionally be desirable to run a Java program without any of Sun's API available. If the compiler produced code using StringBuffer, the JVM might report a "StringBuffer class not found", despite the fact that the original source code never mentions StringBuffer.
- Oliver
Mike Schilling - 09 Jun 2006 21:32 GMT >>> A dumb compiler would presumably create 3.1 transient strings >>> for [quoted text clipped - 20 lines] > report a "StringBuffer class not found", despite the fact that the > original source code never mentions StringBuffer. If the core java.xxx classes aren't present, it isn't Java. StringBuffer is no less part of Java than String, Object, or Exception (or int and boolean, for that matter.)
Jussi Piitulainen - 09 Jun 2006 21:45 GMT >>> A dumb compiler would presumably create 3.1 transient strings >>> for [quoted text clipped - 20 lines] > JVM might report a "StringBuffer class not found", despite the fact > that the original source code never mentions StringBuffer. I think it would need to have something equivalent internally anyway, to implement string concatenation.
And wouldn't it then throw ClassNotFound on String when creating those excess strings? I don't quite believe in the scenario.
Oliver Wong - 12 Jun 2006 16:14 GMT >> Why would even a dumb compiler >> produce worse code? > > Perhaps because it depends on knowledge of the API. It might be > occasionally be desirable to run a Java program without any of Sun's API > available. If the compiler produced code using StringBuffer [obviously, I meant String instead of StringBuffer here]
> , the JVM might report a "StringBuffer class not found", despite the fact > that the original source code never mentions StringBuffer. I mentioned this mainly because in this competition I had entered for writing an optimizing Java compiler, I had taken advantage of the fact that I knew the behaviour of the StringBuffer class to replace certain calls with others. If I recall correctly, it was something like changing this:
<pseudo bytecode> invoke 0 parameter constructor of StringBuffer. dup push "Foo" invoke 1 parameter append method. dup push "Bar" invoke 1 parameter append method. invoke 0 parameter toString </pseudo bytecode>
to this:
<pseudo bytecode> push "Foo" invoke 1 parameter constructor of StringBuffer. dup push "Bar" invoke 1 parameter append method. invoke 0 parameter toString </pseudo bytecode>
and the judges said I shouldn't have relied on information on the semantics/behaviour of the API, but they let it slide for this competition anyway.
- Oliver
Mike Schilling - 12 Jun 2006 20:53 GMT >>> Why would even a dumb compiler >>> produce worse code? [quoted text clipped - 36 lines] > and the judges said I shouldn't have relied on information on the > semantics/behaviour of the API, Uh-huh. It's OK to use one constructor and the append method, but using a different constructor is cheating. What had they been smoking?
> but they let it slide for this competition anyway. Dale King - 05 Jul 2006 08:44 GMT >>> Why would even a dumb compiler >>> produce worse code? [quoted text clipped - 37 lines] > semantics/behaviour of the API, but they let it slide for this > competition anyway. I remember that the Eclipse compiler generated code like the second one and the code generated ran much slower. I found the link to the thread:
http://dev.eclipse.org/newslists/news.eclipse.tools/msg29599.html
And in particular this message of mine:
http://dev.eclipse.org/newslists/news.eclipse.tools/msg30054.html
 Signature Dale King
Tony - 09 Jun 2006 09:25 GMT > I spent hours trying to figure this out, so for others benifit, here it > is: [quoted text clipped - 11 lines] > Anyway, there you have it. > -Mike 1. char is actually of type integer as mentioned by earlier replier 2. Maybe you can solve like this: String str = String.valueOf(s1.charAt(0)) + String.valueOf(s1.charAt(5));
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|