Як уникнути дублювання коду щодо примітивних типів?


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.Так. (Зазвичай це не є великою проблемою, оскільки рідко для однієї програми потрібно більше кількох різних примітивів. Ви також можете "виправити" це, помістивши примітиви всередину класу та використовуючи серіалізацію об'єктів, хоча це може бути досить повільним. )
markpace

3
Крім того, (щойно це запам'яталося), якщо ви читаєте масові примітиви, на зразок вашого коду, схоже, вказує, використовуючи ByteBufferметоди, як-от asDoubleBuffer()або asShortBuffer()вивантажте деякі роботи найнижчого рівня. docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/…
markpace

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

(Код складається, але не перевіряється!)


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

Дублювання було вирішено ціною певної продуктивності, незначною відсутністю безпеки типу компіляції та використання рефлексії.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.