Java7에서 개선된 언어기능: 바이너리 리터럴(Binary Literals)

Java7에 추가된 Java 언어의 7가지 개선사항 중 본 포스트에서는 "Binary Literals"에 대해 정리합니다. 7가지 개선사항은 다음과 같습니다.(OpenJDK: "Project Coin", JSR-334)
  • Binary Literals
  • Underscores in Numeric Literals
  • Strings in switch Statements
  • The try-with-resources Statement
  • Catching Multiple Exception Types and Rethrowing Exceptions with Improved Type Checking
  • Type Inference for Generic Instance Creation
  • Improved Compiler Warnings and Errors When Using Non-Reifiable Formal Parameters with Varargs Methods



Java7 이전까지는 정수형 상수를 표기할때 바이너리 표기법(예. 0110101)이 허용되지 않았습니다. 그 대안으로 바이너리 표기법에 해당하는 문자열을 정수로 변환하여 사용하는 우회법을 사용했는데 다음 예와 같습니다.
int seven = Integer.parseInt("0111", 2);
System.out.println(seven);
7

Java7에서는 정수형 타입(byte, short, int, long)의 상수를 표기할 때 바이너리 표기법을 지원하며, 이때 0b 또는 0B prefix를 함께 기술합니다. 다음은 몇 가지 바이너리 표기법을 이용한 정수형 상수의 예제입니다.
// An 8-bit 'byte' value:
byte aByte = (byte)0b00100001;

// A 16-bit 'short' value:
short aShort = (short)0b1010000101000101;

// Some 32-bit 'int' values:
int anInt1 = 0b10100001010001011010000101000101;
int anInt2 = 0b101;
int anInt3 = 0B101; // The B can be upper or lower case.

// A 64-bit 'long' value. Note the "L" suffix:
long aLong = 0b1010000101000101101000010100010110100001010001011010000101000101L;

바이너리 표기법은 데이터의 비트패턴을 좀 더 명확하게 보여주는 장점이 있습니다. 16진수 형태로 표기된 아래 데이터들의 관계는 쉽게 파악하기 어렵습니다.
public static final int[] phases = {
    0x31, 0x62, 0xC4, 0x89, 0x13, 0x26, 0x4C, 0x98
}
반대로 같은 데이터를 바이너리 표기법으로 기술한 경우, 데이터들 간에 1bit 이동한 관계를 명확히 알 수 있습니다.
public static final int[] phases = {
  0b00110001,
  0b01100010,
  0b11000100,
  0b10001001,
  0b00010011,
  0b00100110,
  0b01001100,
  0b10011000
}
Low-level의 기계어나 비트맵 데이터도 바이너리 표기법이 readable한 장점을 가지고 있습니다.
[8-bit Machine Simulator Verification Code]
public State decodeInstruction(int instruction, State state) {
  if ((instruction & 0b11100000) == 0b00000000) {
    final int register = instruction & 0b00001111;
    switch (instruction & 0b11110000) {
      case 0b00000000: return state.nop();
      case 0b00010000: return state.copyAccumTo(register);
      case 0b00100000: return state.addToAccum(register);
      case 0b00110000: return state.subFromAccum(register);
      case 0b01000000: return state.multiplyAccumBy(register);
      case 0b01010000: return state.divideAccumBy(register);
      case 0b01100000: return state.setAccumFrom(register);
      case 0b01110000: return state.returnFromCall();
      default: throw new IllegalArgumentException();
    }
  } else {
    final int address = instruction & 0b00011111;
    switch (instruction & 0b11100000) {
      case 0b00100000: return state.jumpTo(address);
      case 0b01000000: return state.jumpIfAccumZeroTo(address);
      case 0b01000000: return state.jumpIfAccumNonzeroTo(address);
      case 0b01100000: return state.setAccumFromMemory(address);
      case 0b10100000: return state.writeAccumToMemory(address);
      case 0b11000000: return state.callTo(address);
      default: throw new IllegalArgumentException();
    }
  }
}
[Bitmap for Smile Face]
public static final short[] HAPPY_FACE = {
   (short)0b0000011111100000;
   (short)0b0000100000010000;
   (short)0b0001000000001000;
   (short)0b0010000000000100;
   (short)0b0100000000000010;
   (short)0b1000011001100001;
   (short)0b1000011001100001;
   (short)0b1000000000000001;
   (short)0b1000000000000001;
   (short)0b1001000000001001;
   (short)0b1000100000010001;
   (short)0b0100011111100010;
   (short)0b0010000000000100;
   (short)0b0001000000001000;
   (short)0b0000100000010000;
   (short)0b0000011111100000;
}

[참고문헌]
1. Java Magazine 2011 Premiere
2. Java SE 7 Features and Enhancements

0 댓글