Converting char(s) into String

P

ponga

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
 
J

John O'Conner

ponga said:
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);


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));
 
T

Thomas Hawtin

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
 
A

amitdev

Thomas said:
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();

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) });
 
M

Mike Schilling

ponga said:
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?

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.
 
T

Tony

ponga said:
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

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));
 
C

Chris Uppal

Mike said:
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
 
T

Thomas Hawtin

Thomas said:
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
 
D

Dimitri Maziuk

Mike Schilling sez:
ponga said:
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?

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.

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
 
T

Thomas Hawtin

Dimitri said:
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.

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

}
 
J

Jussi Piitulainen

Dimitri said:
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.

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?
 
O

Oliver Wong

Jussi Piitulainen said:
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?

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
 
M

Mike Schilling

Oliver Wong said:
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.

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.)
 
J

Jussi Piitulainen

Oliver said:
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.

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.
 
O

Oliver Wong

Oliver Wong said:
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
 
M

Mike Schilling

Oliver Wong said:
Oliver Wong said:
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,

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?
 
D

Dale King

Oliver said:
Oliver Wong said:
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.

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
 

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
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top