如何避免有关原始类型的代码重复?


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.对。(通常这不是什么大问题,因为很少有程序需要多个不同的原语。您也可以通过将原语放入类中并使用对象序列化来“修复”此问题,尽管这样做可能会比较慢。 )
markspace

3
另外,(记住这一点)如果您正在读取大量的原语(如您的代码似乎表明),请使用或ByteBuffer这类方法来卸载一些最低级别的工作。 docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/...asDoubleBuffer()asShortBuffer()
markspace

1
注意,有一些努力将原始的通用支持引入Java,List<int>例如etc。可能在2-5年左右的时间内发布。它被称为瓦尔哈拉计划。
Zabuzard

Answers:


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

一种可能会导致性能下降的可能性是,将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);
}

解决该重复问题的代价是一些性能,略微缺乏编译时类型的安全性以及使用反射。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.