StringBuilder
からを作成する方法はありbyte[]
ますか?
を使用してメモリ使用量を改善したいのですStringBuilder
が、最初に持っているのは であるbyte[]
ため、 から を作成してString
から からをbyte[]
作成する必要があり、このソリューションが最適とは思えません。StringBuilder
String
ありがとう
基本的に、最善の選択肢はCharsetDecoderを直接使用することです。
方法は次のとおりです。
byte[] srcBytes = getYourSrcBytes();
//Whatever charset your bytes are endoded in
Charset charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder();
//ByteBuffer.wrap simply wraps the byte array, it does not allocate new memory for it
ByteBuffer srcBuffer = ByteBuffer.wrap(srcBytes);
//Now, we decode our srcBuffer into a new CharBuffer (yes, new memory allocated here, no can do)
CharBuffer resBuffer = decoder.decode(srcBuffer);
//CharBuffer implements CharSequence interface, which StringBuilder fully support in it's methods
StringBuilder yourStringBuilder = new StringBuilder(resBuffer);
追加した:
いくつかのテストの後、単純なもののnew String(bytes)
方がはるかに高速であり、それよりも高速にする簡単な方法はないようです。これが私が実行したテストです:
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.text.ParseException;
public class ConsoleMain {
public static void main(String[] args) throws IOException, ParseException {
StringBuilder sb1 = new StringBuilder("abcdefghijklmnopqrstuvwxyz");
for (int i=0;i<19;i++) {
sb1.append(sb1);
}
System.out.println("Size of buffer: "+sb1.length());
byte[] src = sb1.toString().getBytes("UTF-8");
StringBuilder res;
long startTime = System.currentTimeMillis();
res = testStringConvert(src);
System.out.println("Conversion using String time (msec): "+(System.currentTimeMillis()-startTime));
if (!res.toString().equals(sb1.toString())) {
System.err.println("Conversion error");
}
startTime = System.currentTimeMillis();
res = testCBConvert(src);
System.out.println("Conversion using CharBuffer time (msec): "+(System.currentTimeMillis()-startTime));
if (!res.toString().equals(sb1.toString())) {
System.err.println("Conversion error");
}
}
private static StringBuilder testStringConvert(byte[] src) throws UnsupportedEncodingException {
String s = new String(src, "UTF-8");
StringBuilder b = new StringBuilder(s);
return b;
}
private static StringBuilder testCBConvert(byte[] src) throws CharacterCodingException {
Charset charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder();
ByteBuffer srcBuffer = ByteBuffer.wrap(src);
CharBuffer resBuffer = decoder.decode(srcBuffer);
StringBuilder b = new StringBuilder(resBuffer);
return b;
}
}
結果:
Size of buffer: 13631488
Conversion using String time (msec): 91
Conversion using CharBuffer time (msec): 252
また、IDEONE の変更された (メモリ消費量が少ない) バージョン:こちら.
必要なステートメントが短い場合は、間にある String ステップを回避する方法はありません。String コンストラクターは、非常に一般的なケースで便宜上変換とオブジェクト構築を組み合わせますが、StringBuilder にはそのような便利なコンストラクターはありません。
パフォーマンスに関心がある場合は、次のようなものを使用して、中間の String オブジェクトを回避できます。
new StringBuilder(Charset.forName(charsetName).decode(ByteBuffer.wrap(inBytes)))
パフォーマンスを微調整したい場合は、デコード プロセスを自分で制御できます。たとえば、必要なメモリ量の見積もりとして averageCharsPerByte を使用することで、メモリの使用量が多すぎないようにすることができます。その見積もりが短すぎる場合にバッファーのサイズを変更する代わりに、結果の StringBuilder を使用してすべての部分を蓄積することができます。
CharsetDecoder cd = Charset.forName(charsetName).newDecoder();
cd.onMalformedInput(CodingErrorAction.REPLACE);
cd.onUnmappableCharacter(CodingErrorAction.REPLACE);
int lengthEstimate = Math.ceil(cd.averageCharsPerByte()*inBytes.length) + 1;
ByteBuffer inBuf = ByteBuffer.wrap(inBytes);
CharBuffer outBuf = CharBuffer.allocate(lengthEstimate);
StringBuilder out = new StringBuilder(lengthEstimate);
CoderResult cr;
while (true) {
cr = cd.decode(inBuf, outBuf, true);
out.append(outBuf);
outBuf.clear();
if (cr.isUnderflow()) break;
if (!cr.isOverflow()) cr.throwException();
}
cr = cd.flush(outBuf);
if (!cr.isUnderflow()) cr.throwException();
out.append(outBuf);
ただし、上記のコードがほとんどのアプリケーションで努力する価値があるとは思えません。アプリケーションがパフォーマンスにそれほど関心がある場合は、おそらく StringBuilder も処理するべきではなく、バッファ レベルですべてを処理する必要があります。