Bagaimana cara menghindari duplikasi kode mengenai tipe primitif?

9

Latar Belakang

Input stream bit didukung oleh array byte. Ada beberapa metode yang membaca dari array byte itu ke berbagai array primitif yang dipaksakan.

Masalah

Ada kode duplikat. Java tidak memiliki generik pada tipe primitif, jadi mungkin pengulangan tidak dapat dihindari.

Kode

Kode berulang terlihat dalam metode berikut:

@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;
}

Perhatikan bagaimana final byte[] outberhubungan dengan readByte(bits)seperti final short[] outberkaitan dengan readShort(bits). Hubungan-hubungan ini adalah inti masalahnya.

Pertanyaan

Bagaimana duplikasi dapat dihilangkan, jika sama sekali, tanpa menimbulkan hit kinerja yang signifikan (misalnya, dengan autoboxing)?

Terkait

Dave Jarvis
sumber
6
Tidak, tidak ada yang bisa Anda lakukan di sana. Duplikasi adalah satu-satunya pilihan.
Andy Turner
Gunakan koleksi primitif pihak ketiga
Vince Emigh
1
Java lacks generics on primitive types, so perhaps the repetition is unavoidable.Ya. (Biasanya itu tidak banyak masalah, karena jarang satu program membutuhkan lebih dari beberapa primitif yang berbeda. Anda juga bisa "memperbaiki" ini dengan meletakkan primitif di dalam kelas dan menggunakan serialisasi objek, meskipun itu bisa relatif lambat. )
markspace
3
Juga, (baru ingat ini) jika Anda membaca primitif massal seperti kode Anda tampaknya menunjukkan, menggunakan ByteBuffermetode seperti asDoubleBuffer()atau asShortBuffer()akan membongkar beberapa pekerjaan tingkat terendah. docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/…
markspace
1
Perhatikan bahwa ada beberapa upaya untuk membawa dukungan generik primitif ke Jawa, misalnya, List<int>dll. Rilis dalam mungkin 2-5 tahun atau lebih. Ini disebut Project Valhalla.
Zabuzard

Jawaban:

2

Jika Anda membaca primitif massal seperti kode Anda tampaknya menunjukkan, menggunakan metode ByteBuffer seperti asDoubleBuffer () atau asShortBuffer () akan mengeluarkan beberapa pekerjaan tingkat terendah.

Contoh:

   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`
   }

(Kode mengkompilasi tetapi tidak diuji!)

markspace
sumber
0

Satu kemungkinan, yang akan dikenakan penalti kinerja, adalah menggunakan java.lang.reflect.Arrayuntuk memperlakukan array sebagai Objek yang kemudian mengizinkan penggunaan kembali kode yang sama di semua metode yang dibaca.

@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);
}

Duplikasi telah ditangani dengan mengorbankan beberapa kinerja, kurangnya jenis keamanan waktu kompilasi, dan penggunaan refleksi.

Dave Jarvis
sumber