web-dev-qa-db-ja.com

プリミティブ型に関するコードの重複を回避するにはどうすればよいですか?

バックグラウンド

ビット入力ストリームは、バイトの配列に支えられています。そのバイト配列からさまざまな強制プリミティブ配列に読み取るメソッドがいくつかあります。

問題

コードが重複しています。 Javaにはプリミティブ型のジェネリックがないため、おそらく繰り返しは避けられません。

コード

反復的なコードは、次のメソッドで明らかです。

@Override
public long readBytes(final byte[] out, final int offset, final int count, final int bits) {
    final int total = offset + count;

    assert out != null;
    assert total <= out.length;

    final long startPosition = position();

    for (int i = offset; i < total; i++) {
        out[i] = readByte(bits);
    }

    return position() - startPosition;
}

@Override
public long readShorts(final short[] out, final int offset, final int count, final int bits) {
    final int total = offset + count;

    assert out != null;
    assert total <= out.length;

    final long startPosition = position();

    for (int i = offset; i < total; i++) {
        out[i] = readShort(bits);
    }

    return position() - startPosition;
}

final byte[] outreadByte(bits)final short[] outreadShort(bits)に関連しています。これらの関係は問題の核心です。

質問

(オートボクシングなどによって)パフォーマンスに大きな影響を与えることなく、重複を排除するにはどうすればよいでしょうか。

関連した

9
Dave Jarvis

コードが示すようにバルクプリミティブを読み取っている場合、 asDoubleBuffer() または asShortBuffer() のようなメソッド ByteBuffer を使用すると、最低レベルの作業。

例:

   public void readBytes( final byte[] out, final int offset, final int count, final ByteBuffer buffer ) {
      buffer.get( out, offset, count );  // udates ByteBuffer `position` automatically
   }

   public void readShorts( final short[] out, final int offset, final int count, final ByteBuffer buffer ) {
      ShortBuffer sb = buffer.asShortBuffer();
      sb.get( out, offset, count );  // note that `count` reads two bytes for each `short`
   }

(コードはコンパイルされますが、テストされていません!)

2
markspace

パフォーマンスが低下する可能性の1つは、 Java.lang.reflect.Array を使用して配列をオブジェクトとして扱い、すべての読み取りメソッドで同じコードを再利用できるようにすることです。

@FunctionalInterface
public interface BitArrayReader {
    Object read(int bits);
}

private long readPrimitive(
        final Object out, final int offset, final int count, final int bits,
        final BitArrayReader reader) {
    final int total = offset + count;

    assert out != null;
    assert total <= Array.getLength(out);

    final long startPosition = position();

    for (int i = offset; i < total; i++) {
        Array.set(out, i, reader.read(bits));
    }

    return position() - startPosition;
}

@Override
public long readBooleans(boolean[] out, int offset, int count, int bits) {
    return readPrimitive(out, offset, count, bits, this::readBoolean);
}

一部のパフォーマンス、コンパイル時の型安全性のわずかな欠如、およびリフレクションの使用を犠牲にして、重複が対処されました。

0
Dave Jarvis