Как избежать дублирования кода относительно примитивных типов?

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
Нет, вы ничего не можете сделать там. Дублирование - единственный вариант.
Энди Тернер
Используйте стороннюю примитивную коллекцию
Винс Эми
1
Java lacks generics on primitive types, so perhaps the repetition is unavoidable.Ага. (Обычно это не большая проблема, поскольку одной программе редко требуется больше, чем несколько разных примитивов. Вы также можете «исправить» это, поместив примитивы в класс и используя сериализацию объектов, хотя это может быть относительно медленным. )
отмечается
3
Кроме того, (только что вспомнили), если вы читаете массовые примитивы, как, кажется, указывает ваш код, использование ByteBufferтаких методов, как asDoubleBuffer()или asShortBuffer()будет снимать часть работы самого низкого уровня. docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/…
markspace
1
Обратите внимание, что предпринимаются некоторые усилия по обеспечению примитивной общей поддержки Java, List<int>т. Е. И т. Д. Выпуск может быть через 2-5 лет или около того. Это называется Project Valhalla.
Забузард

Ответы:

2

Если вы читаете объемные примитивы , как ваш код , кажется, указывает, используя ByteBuffer методы , как asDoubleBuffer () или asShortBuffer () будет разгрузить часть самого низкого уровня работы.

Пример:

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

(Код компилируется, но не тестируется!)

markspace
источник
0

Одна возможность, которая повлечет за собой снижение производительности, заключается в использовании 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);
}

Дублирование было решено за счет некоторой производительности, незначительного отсутствия безопасности типа во время компиляции и использования отражения.

Дейв Джарвис
источник