Java Code Geeksの Webサイトでは、時折、
Java Best Practicesシリーズ(実稼働実績のあるソリューション)の投稿を公開してい
ます 。 著者から許可を得て、私は投稿の1つを翻訳しました。 もっともっと。
Javaプログラミングのいくつかの側面に関する一連の記事を
続けて、特にデフォルトのエンコードが使用されている場合に
文字をバイトシーケンスに、またはその逆に変換する場合の
Stringのパフォーマンスに触れます。 結論として、文字をバイトシーケンスに、またはその逆に変換するための非古典的アプローチと古典的アプローチのパフォーマンス比較を適用します。
すべての研究は
、電気通信業界向けの非常に効率的な
システム(電気通信業界向けの超高性能生産システム)の開発における問題に基づいています。
記事の各パートの前に、追加情報とコード例について
Java APIに精通することを強くお勧めします。
以下の特性を備えたSony Vaioで実験が行われました。
OS:openSUSE 11.1(x86_64)
プロセッサー(CPU):Intel®Core(TM)2 Duo CPU T6670 @ 2.20GHz
周波数:1,200.00 MHz
RAM:2.8 GB
Java:OpenJDK 1.6.0_0 64ビット
次のオプションを使用します。
同時にスレッド:1
実験の反復回数:1,000,000
合計テスト:100
CharをByteに 、またはその逆に変換します。
Charを
Byteに 、またはその逆に変換するタスクは、プログラマーがバイトシーケンスの処理、
Stringのシリアル化、プロトコルの実装などを行わなければならない通信の分野で広く行われています。
Javaには 、このためのツールセットがあり
ます 。
Stringクラスの
getBytes(charsetName)メソッドは、おそらく
Stringをその同等のバイトに変換するための最も一般的なツールの1つです。 charsetNameパラメーターは
文字列エンコードを指します;このメソッドがない場合、OSのデフォルトのエンコードを使用して、
文字列をバイトシーケンスにエンコードします。
文字配列を同等のバイトに変換する別の古典的なアプローチは、
NIO (
New Input Output )パッケージの
ByteBufferクラスを使用することです。
どちらのアプローチも一般的であり、もちろん非常に使いやすいですが、より具体的な方法と比較して、深刻なパフォーマンスの問題が発生します。 覚えておいてください:あるエンコーディングから別のエンコーディングに変換するわけではありません。このため、
「String.getBytes(charsetName)」または
NIOパッケージの機能を使用した「クラシック」アプローチ
に従う必要があります。
ASCIIの場合、次のコードがあります。
public static byte[] stringToBytesASCII(String str) { char[] buffer = str.toCharArray(); byte[] b = new byte[buffer.length]; for (int i = 0; i < b.length; i++) { b[i] = (byte) buffer[i]; } return b; }
配列bは、それぞれが1バイトを占める
ASCII範囲(0-127)の文字を考慮に入れながら、各文字の値をそのバイト相当にキャストすることによって作成されます。
コンストラクター
「new String(byte [])」を使用して、配列bを文字列に戻すことができます。
System.out.println(new String(stringToBytesASCII("test")));
デフォルトのエンコードでは、次のコードを使用できます。
public static byte[] stringToBytesUTFCustom(String str) { char[] buffer = str.toCharArray(); byte[] b = new byte[buffer.length << 1]; for(int i = 0; i < buffer.length; i++) { int bpos = i << 1; b[bpos] = (byte) ((buffer[i]&0xFF00)>>8); b[bpos + 1] = (byte) (buffer[i]&0x00FF); } return b; }
Javaの各文字には2バイトが必要です。文字列を同等のバイトに変換するには、文字列の各文字を2バイト相当に変換する必要があります。
そして行に戻ります:
public static String bytesToStringUTFCustom(byte[] bytes) { char[] buffer = new char[bytes.length >> 1]; for(int i = 0; i < buffer.length; i++) { int bpos = i << 1; char c = (char)(((bytes[bpos]&0x00FF)<<8) + (bytes[bpos+1]&0x00FF)); buffer[i] = c; } return new String(buffer); }
文字列の各文字を対応する2バイト文字から回復し、再度
String(char [])コンストラクターを使用して、新しいオブジェクトを作成します。
NIOパッケージの機能をタスクに使用する例:
public static byte[] stringToBytesUTFNIO(String str) { char[] buffer = str.toCharArray(); byte[] b = new byte[buffer.length << 1]; CharBuffer cBuffer = ByteBuffer.wrap(b).asCharBuffer(); for(int i = 0; i < buffer.length; i++) cBuffer.put(buffer[i]); return b; } public static String bytesToStringUTFNIO(byte[] bytes) { CharBuffer cBuffer = ByteBuffer.wrap(bytes).asCharBuffer(); return cBuffer.toString(); }
そして今、約束されたように、グラフィックス。
バイト配列の文字列 :

横軸はテストの数、縦軸は各テストの1秒あたりの操作数です。 高いほど速くなります。 予想どおり、
「String.getBytes()」および
「stringToBytesUTFNIO(String)」は、
「stringToBytesASCII(String)」および
「stringToBytesUTFCustom(String)」よりもはるかに
うまく機能しませんでした 。 ご覧のとおり、実装により、1秒あたりの操作数がほぼ30%増加しました。
文字 列への
バイト配列 :

結果は再び元気づけられます。 独自の方法では、
「new String(byte [])」と比較して1秒あたりの操作数が15%増加し、
「bytesToStringUTFNIO(byte [])」と比較して1秒あたりの操作数が30%増加しました。
結論として、バイトシーケンスを文字列に、またはその逆に変換する必要があり、エンコードを変更する必要がない場合、自己記述メソッドを使用すると、顕著なパフォーマンスの向上を得ることができます。 その結果、私たちの方法は、従来のアプローチと比較して合計45%の加速を達成しました。
ハッピーコーディング。