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


9

バックグラウンド

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

問題

コードが重複しています。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[] outすることに関するreadByte(bits)同じようfinal short[] outにも関しますreadShort(bits)。これらの関係は問題の核心です。

質問

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

関連した


6
いいえ、そこでは何もできません。複製が唯一のオプションです。
アンディターナー

サードパーティのプリミティブコレクションを使用する
Vince Emigh

1
Java lacks generics on primitive types, so perhaps the repetition is unavoidable.うん。(1つのプログラムが複数のプリミティブを必要とすることはまれであるため、通常はそれほど問題ではありません。クラス内にプリミティブを配置し、オブジェクトのシリアル化を使用することでこれを「修正」することもできますが、比較的遅い場合があります。 )
マークスペース

3
あなたのコードが示すように見えるように、バルクプリミティブを読んで使用している場合も、(これだけのことを思い出した)ByteBufferのようなメソッドをasDoubleBuffer()またはasShortBuffer()最低レベルの作業の一部をオフロードします。 docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/...
markspace

1
Javaにプリミティブな一般的なサポートを提供するためのいくつかの取り組みがあることに注意してくださいList<int>。これはProject Valhallaと呼ばれます。
ザブザード

回答:


2

コードのようにバルクプリミティブを読み取っている場合、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`
   }

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


0

パフォーマンスが低下する可能性の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);
}

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.