기본 유형과 관련된 코드의 중복을 피하는 방법은 무엇입니까?


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
아니, 거기서 할 수있는 일은 없어 복제가 유일한 옵션입니다.
Andy Turner

타사 기본 컬렉션
Vince Emigh

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라고합니다.
Zabuzard

답변:


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은 배열을 Object로 취급하여 모든 읽기 방법에서 동일한 코드를 재사용 할 수 있도록하는 것입니다.

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

중복은 약간의 성능, 컴파일 타임 유형 안전성의 미미한 부족 및 리플렉션 사용으로 해결되었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.