1.はじめに

Javaでは

String

配列と

byte

配列の間で頻繁に変換する必要があります。

このチュートリアルでは、これらの操作について詳しく説明します。

まず、

String



byte

配列に変換するさまざまな方法を見ていきます。次に、同様の操作を逆に見ていきます。

2.

String

から

Byte

配列への変換


String

は、JavaではUnicode文字の配列として格納されています。それを

byte

配列に変換するために、文字のシーケンスをバイトのシーケンスに変換します。この翻訳では、**


Charset


のインスタンスを使用します。

このクラスは、一連の

__char


sと一連の


byte

__s ** の間のマッピングを指定します。

上記のプロセスを

encoding

と呼びます。

Javaでは

String



byte

配列にエンコードすることができます。

例を使ってそれぞれを詳しく見てみましょう。

2.1.

String.getBytes()

を使用する

(String charsetName)

] – 名前付き文字セットを使用してエンコードします
**

https://docs.oracle.com/javase/10/docs/api/java/lang/String.html#getBytes(java.nio.charset.Charset

)[

getBytes

(Charset charset)__] – 与えられた文字セットを使ってエンコードします

まず、プラットフォームのデフォルトの文字セットを使って文字列をエンコードしましょう。

String inputString = "Hello World!";
byte[]byteArrray = inputString.getBytes();

上記の方法はプラットフォームのデフォルトの文字セットを使用するため、プラットフォームに依存します。この文字セットは

Charset.defaultCharset()

を呼び出すことで取得できます。

次に、名前付き文字セットを使用して文字列をエンコードしましょう。

@Test
public void whenGetBytesWithNamedCharset__thenOK()
  throws UnsupportedEncodingException {
    String inputString = "Hello World!";
    String charsetName = "IBM01140";

    byte[]byteArrray = inputString.getBytes("IBM01140");

    assertArrayEquals(
      new byte[]{ -56, -123, -109, -109, -106, 64, -26,
        -106, -103, -109, -124, 90 },
      byteArrray);
}

名前付き文字セットがサポートされていない場合、このメソッドは

UnsupportedEncodingException

をスローします。

入力に文字セットでサポートされていない文字が含まれている場合、上記の2つのバージョンの動作は未定義です。対照的に、3番目のバージョンは、サポートされていない入力をエンコードするために文字セットのデフォルトの置換バイト配列を使用します。

次に、** getBytes()

メソッドの3番目のバージョンを呼び出して、

Charsetのインスタンスを渡します。

@Test
public void whenGetBytesWithCharset__thenOK() {
    String inputString = "Hello ਸੰਸਾਰ!";
    Charset charset = Charset.forName("ASCII");

    byte[]byteArrray = inputString.getBytes(charset);

    assertArrayEquals(
      new byte[]{ 72, 101, 108, 108, 111, 32, 63, 63, 63,
        63, 63, 33 },
      byteArrray);
}

ここでは、ファクトリメソッドhttps://docs.oracle.com/javase/10/docs/api/java/nio/charset/Charset.html#forName(java.lang.String)[

Charset.forName

]を使用します。

Charset

のインスタンスを取得します。要求された文字セットの名前が無効な場合、このメソッドは実行時例外をスローします。現在のJVMで文字セットがサポートされている場合は、ランタイム例外もスローされます。

ただし、一部の文字セットはすべてのJavaプラットフォームで使用できることが保証されています。


StandardCharsets


クラスは、これらの文字セットの定数を定義します。

最後に、** 標準の文字セットを使ってエンコードしましょう:

@Test
public void whenGetBytesWithStandardCharset__thenOK() {
    String inputString = "Hello World!";
    Charset charset = StandardCharsets.UTF__16;

    byte[]byteArrray = inputString.getBytes(charset);

    assertArrayEquals(
      new byte[]{ -2, -1, 0, 72, 0, 101, 0, 108, 0, 108, 0,
        111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 100, 0, 33 },
      byteArrray);
}

したがって、さまざまな

getBytes

バージョンの確認を完了します。次に、

Charset

自体が提供するメソッドを見てみましょう。

2.2. __Charset.encode()を使う


  • Charset

    クラスは、Unicode文字をバイトにエンコードする便利なメソッドである

    encode()

    を提供します** このメソッドは、常に無効な入力とマップ不可能な文字を、文字セットのデフォルトの置換バイト配列を使って置き換えます。


  • String



    byte

    配列に変換するために

    encode

    メソッドを使いましょう:**

@Test
public void whenEncodeWithCharset__thenOK() {
    String inputString = "Hello ਸੰਸਾਰ!";
    Charset charset = StandardCharsets.US__ASCII;

    byte[]byteArrray = charset.encode(inputString).array();

    assertArrayEquals(
      new byte[]{ 72, 101, 108, 108, 111, 32, 63, 63, 63, 63, 63, 33 },
      byteArrray);
}

上記のように、サポートされていない文字は文字セットのデフォルトの置き換え

byte

63に置き換えられました。

これまで使用されてきたアプローチは、https://docs.oracle.com/javase/10/docs/api/java/nio/charset/CharsetEncoder.html[

CharsetEncoder

]クラスを内部的に使用してエンコードを実行します。次のセクションでこのクラスを調べましょう。

2.3.

CharsetEncoder


  • CharsetEncoder

    は、与えられた文字セット** に対してUnicode文字を一連のバイトに変換します。さらに、エンコード処理を細かく制御できます。

このクラスを使用して、

String



byte

配列に変換しましょう。

@Test
public void whenUsingCharsetEncoder__thenOK()
  throws CharacterCodingException {
    String inputString = "Hello ਸੰਸਾਰ!";
    CharsetEncoder encoder = StandardCharsets.US__ASCII.newEncoder();
    encoder.onMalformedInput(CodingErrorAction.IGNORE)
      .onUnmappableCharacter(CodingErrorAction.REPLACE)
      .replaceWith(new byte[]{ 0 });

    byte[]byteArrray = encoder.encode(CharBuffer.wrap(inputString))
                          .array();

    assertArrayEquals(
      new byte[]{ 72, 101, 108, 108, 111, 32, 0, 0, 0, 0, 0, 33 },
      byteArrray);
}

ここでは、

Charset

オブジェクトに対して

__newEncoder


methodを呼び出して、

CharsetEncoder__のインスタンスを作成します。

次に、

onMalformedInput()

および

__onUnmappableCharacter()


methods


を呼び出して、エラー状態に対するアクションを指定します。

__以下のアクションを指定できます。

  • IGNORE – 誤った入力をドロップする

  • REPLACE – 誤った入力を置き換えます

  • REPORT – を返してエラーを報告する



CoderResult


オブジェクトまたはhttps://docs.oracle.com/javase/10/docs/を投入api/java/nio/charset/CoderResult.html[

CharacterCodingException

]

さらに、置換

byte

配列を指定するために

replaceWith()

メソッドを使用しています。

このようにして、文字列をバイト配列に変換するためのさまざまなアプローチのレビューを完了します。次に逆の操作を見てみましょう。

3.バイト配列を文字列に変換する


  • byte

    配列を

    String

    に変換する処理を

    decoding

    ** と呼びます。エンコードと同様に、このプロセスには

    Charset

    が必要です。

ただし、バイト配列をデコードするために文字セットを使用することはできません。


String



byte

配列

にエンコードするために使用された文字セットを使用する必要があります。

バイト配列を文字列に変換する方法はたくさんあります。それぞれを詳しく調べてみましょう。

3.1.

String

コンストラクタを使用する


  • String

    クラスには、入力として

    byte

    配列を取るコンストラクタがほとんどありません** 。それらはすべて

    getBytes

    メソッドに似ていますが、逆に機能します。

まず、プラットフォームのデフォルトの文字セットを使用して、バイト配列を

String

に変換しましょう。

@Test
public void whenStringConstructorWithDefaultCharset__thenOK() {
    byte[]byteArrray = { 72, 101, 108, 108, 111, 32, 87, 111, 114,
      108, 100, 33 };

    String string = new String(byteArrray);

    assertNotNull(string);
}

  • デコードされた文字列の内容については、ここでは何も主張しません。これは、プラットフォームのデフォルトの文字セットによっては異なるデコードになる可能性があるためです。**

このため、一般的にこの方法は避けてください。

次に、デコードに名前付き文字セットを使用しましょう。

@Test
public void whenStringConstructorWithNamedCharset__thenOK()
    throws UnsupportedEncodingException {
    String charsetName = "IBM01140";
    byte[]byteArrray = { -56, -123, -109, -109, -106, 64, -26, -106,
      -103, -109, -124, 90 };

    String string = new String(byteArrray, charsetName);

    assertEquals("Hello World!", string);
}

指定された文字セットがJVM上で利用できない場合、このメソッドは例外をスローします。

3番目に、デコードを行うために

Charset

オブジェクトを使用しましょう。

@Test
public void whenStringConstructorWithCharSet__thenOK() {
    Charset charset = Charset.forName("UTF-8");
    byte[]byteArrray = { 72, 101, 108, 108, 111, 32, 87, 111, 114,
      108, 100, 33 };

    String string = new String(byteArrray, charset);

    assertEquals("Hello World!", string);
}

最後に、同じ標準の

Charset

を使用しましょう。

@Test
public void whenStringConstructorWithStandardCharSet__thenOK() {
    Charset charset = StandardCharsets.UTF__16;

    byte[]byteArrray = { -2, -1, 0, 72, 0, 101, 0, 108, 0, 108, 0,
      111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 100, 0, 33 };

    String string = new String(byteArrray, charset);

    assertEquals("Hello World!", string);
}

これまでのところ、コンストラクタを使用して

byte

配列を

String

に変換しました。それでは、他の方法を見てみましょう。

3.2.

Charset.decode()

を使う


Charset

クラスは、

ByteBuffer



String

に変換する

decode()

メソッドを提供します。

@Test
public void whenDecodeWithCharset__thenOK() {
    byte[]byteArrray = { 72, 101, 108, 108, 111, 32, -10, 111,
      114, 108, -63, 33 };
    Charset charset = StandardCharsets.US__ASCII;
    String string = charset.decode(ByteBuffer.wrap(byteArrray))
                      .toString();

    assertEquals("Hello �orl�!", string);
}

ここで、無効な入力は文字セットのデフォルトの置換文字に置き換えられます。

3.3.

CharsetDecoder

内部で復号化するためのこれまでのアプローチはすべて、https://docs.oracle.com/javase/10/docs/api/java/nio/charset/CharsetDecoder.html[

CharsetDecoder

]クラスを使用しています。

  • このクラスをデコードプロセスのきめ細かい制御に直接使用できます。

@Test
public void whenUsingCharsetDecoder__thenOK()
  throws CharacterCodingException {
    byte[]byteArrray = { 72, 101, 108, 108, 111, 32, -10, 111, 114,
      108, -63, 33 };
    CharsetDecoder decoder = StandardCharsets.US__ASCII.newDecoder();

    decoder.onMalformedInput(CodingErrorAction.REPLACE)
      .onUnmappableCharacter(CodingErrorAction.REPLACE)
      .replaceWith("?");

    String string = decoder.decode(ByteBuffer.wrap(byteArrray))
                      .toString();

    assertEquals("Hello ?orl?!", string);
}

ここでは、無効な入力とサポートされていない文字を「?」に置き換えています。

無効な入力があった場合に通知を受けたい場合は、

decoder

を次のように変更できます。

decoder.onMalformedInput(CodingErrorAction.REPORT)
  .onUnmappableCharacter(CodingErrorAction.REPORT)

4.まとめ

この記事では、

String

をバイト配列に変換し、その逆を行う複数の方法を調べました。入力データと無効な入力に必要な制御レベルに基づいて、適切な方法を選択する必要があります。

いつものように、完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/java-strings[over on GitHub]にあります。