【问题标题】:How to avoid duplication of code regarding primitive types?如何避免关于原始类型的代码重复?
【发布时间】:2020-02-27 19:15:57
【问题描述】:

背景

位输入流由字节数组支持。有一些方法可以从该字节数组中读取到各种强制原始数组中。

问题

有重复的代码。 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[] outreadShort(bits) 相关>。这些关系是问题的症结所在。

问题

如何消除重复(如果有的话)而不会对性能造成重大影响(例如,通过自动装箱)?

相关

【问题讨论】:

  • 不,在那里你无能为力。复制是唯一的选择。
  • 使用第三方原始集合
  • Java lacks generics on primitive types, so perhaps the repetition is unavoidable. 是的。 (通常这不是什么大问题,因为一个程序很少需要多个不同的原语。您也可以通过将原语放入类中并使用对象序列化来“解决”这个问题,尽管这可能相对较慢。 )
  • 另外,(只是记住了这一点)如果您正在阅读像您的代码所示的批量原语,使用 ByteBuffer 方法如 asDoubleBuffer()asShortBuffer() 将卸载一些最低级别的工作. docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/…
  • 请注意,有一些努力为 Java 带来原始的泛型支持,即 List&lt;int&gt; 等。可能在 2-5 年左右发布。它被称为瓦尔哈拉计划。

标签: java arrays code-duplication


【解决方案1】:

如果您正在阅读您的代码似乎表明的批量原语,则使用 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`
   }

(代码已编译但未经测试!)

【讨论】:

    【解决方案2】:

    一种会导致性能损失的可能性是使用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);
    }
    

    以牺牲一些性能、编译时类型安全性的轻微不足和反射的使用为代价解决了重复问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-19
      • 1970-01-01
      • 2011-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多