자바의 #ifdef #ifndef


106

C ++의 #ifdef #ifndef와 같이 Java에서 컴파일 시간 조건을 만드는 방법이 있는지 의심됩니다.

내 문제는 Java로 작성된 알고리즘이 있고 해당 알고리즘에 대해 다른 실행 시간이 향상된다는 것입니다. 따라서 각 개선 사항을 사용할 때 절약되는 시간을 측정하고 싶습니다.

지금은 실행 시간 동안 개선해야 할 것과 그렇지 않은 것을 결정하는 데 사용되는 부울 변수 세트가 있습니다. 그러나 이러한 변수를 테스트하는 것조차 총 실행 시간에 영향을줍니다.

그래서 컴파일 시간 동안 프로그램의 어떤 부분을 컴파일하고 사용해야하는지 결정하는 방법을 찾고 싶습니다.

누군가 Java로 수행하는 방법을 알고 있습니까? 또는 누군가가 그러한 방법이 없다는 것을 알고있을 수도 있습니다 (유용 할 수도 있습니다).

답변:


126
private static final boolean enableFast = false;

// ...
if (enableFast) {
  // This is removed at compile time
}

위에 표시된 것과 같은 조건은 컴파일 타임에 평가됩니다. 대신 이것을 사용한다면

private static final boolean enableFast = "true".equals(System.getProperty("fast"));

그러면 enableFast에 종속 된 모든 조건이 JIT 컴파일러에 의해 평가됩니다. 이에 대한 오버 헤드는 무시할 수 있습니다.


이 솔루션은 내 것보다 낫습니다. 미리 설정된 외부 값으로 변수를 초기화하려고했을 때 실행 시간이 3 초로 돌아갔습니다. 그러나 변수를 정적 클래스 변수 (함수 로컬 변수가 아님)로 정의하면 실행 시간이 1 초로 돌아 왔습니다. 도와 주셔서 감사합니다.
jutky

6
IIRC는 Java가 JIT 컴파일러를 갖기 전에도 작동했습니다. javac내가 생각하기에 코드가 제거되었습니다 . 이것은 (예를 들어) enableFast에 대한 표현식이 컴파일 시간 상수 표현식 인 경우에만 작동했습니다 .
Stephen C

2
예,하지만이 조건은 메서드 내에 있어야합니다. 맞습니까? 설정하고 싶은 개인용 정적 최종 문자열이있는 경우는 어떻습니까? (예 : 프로덕션과 스테이징을 위해 다르게 설정된 서버 URL 세트)
tomwhipple

3
@tomwhipple : 사실, 플러스 이것은 당신이 그런 짓을하는 것을 허용하지 않습니다 private void foo(#ifdef DEBUG DebugClass obj #else ReleaseClass obj #endif )
Zonko

3
수입은 어떻습니까 (예 : 클래스 경로에 관한 것)?
n611x007

44

javac는 연결할 수없는 컴파일 된 코드를 출력하지 않습니다. 당신을위한 상수 값에 최종 변수 세트를 사용 #define하고 일반 if에 대한 문 #ifdef.

javap를 사용하여 연결할 수없는 코드가 출력 클래스 파일에 포함되어 있지 않음을 증명할 수 있습니다. 예를 들어, 다음 코드를 고려하십시오.

public class Test
{
   private static final boolean debug = false;

   public static void main(String[] args)
   {
       if (debug) 
       {
           System.out.println("debug was enabled");
       }
       else
       {
           System.out.println("debug was not enabled");
       }
   }
}

javap -c Test 두 경로 중 하나만 컴파일되었음을 나타내는 다음 출력을 제공합니다 (그리고 if 문은 컴파일되지 않음).

public static void main(java.lang.String[]);
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc     #3; //String debug was not enabled
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   return

2
이 javac 특정입니까, 아니면 실제로 JLS에서이 동작을 보장합니까?
Pacerier 2014-06-25

@pacerier, 이것이 JLS에 의해 보장되는지 모르겠지만, 1.1.7 이전의 가능한 예외를 제외하고는 90 년대 이후로 접한 모든 자바 컴파일러에 대해 사실이었습니다. 그런 다음 테스트하십시오.

12

해결책을 찾았다 고 생각합니다. 훨씬 간단합니다.
"최종"수정 자로 부울 변수를 정의하면 Java 컴파일러 자체가 문제를 해결합니다. 이 조건을 테스트 한 결과가 무엇인지 미리 알고 있기 때문입니다. 예를 들어이 코드 :

    boolean flag1 = true;
    boolean flag2 = false;
    int j=0;
    for(int i=0;i<1000000000;i++){
        if(flag1)
            if(flag2)
                j++;
            else
                j++;
        else
            if(flag2)
                j++;
            else
                j++;
    }

내 컴퓨터에서 약 3 초 실행됩니다.
그리고 이것

    final boolean flag1 = true;
    final boolean flag2 = false;
    int j=0;
    for(int i=0;i<1000000000;i++){
        if(flag1)
            if(flag2)
                j++;
            else
                j++;
        else
            if(flag2)
                j++;
            else
                j++;
    }

약 1 초 실행됩니다. 이 코드에 걸리는 시간과 동시에

    int j=0;
    for(int i=0;i<1000000000;i++){
        j++;
    }

1
그것 참 흥미 롭네. JIT가 이미 조건부 컴파일을 지원하는 것 같습니다! 결승전이 다른 클래스 나 다른 패키지에있는 경우 작동합니까?
joeytwiddle 2013 년

큰! 그런 다음 이것이 런타임 최적화라고 생각하며 코드는 실제로 컴파일 타임에 제거되지 않습니다. 성숙한 VM을 사용하는 한 괜찮습니다.
joeytwiddle 2013 년

@joeytwiddle, 키워드는 성숙한 VM을 "사용하는 한"입니다.
Pacerier 2014-06-25

2

사용한 적이 없지만 존재합니다.

JCPP는 C 전 처리기의 완전하고 호환되는 독립형 순수 Java 구현입니다. sablecc, antlr, JLex, CUP 등과 같은 도구를 사용하여 Java로 C 스타일 컴파일러를 작성하는 사람들에게 사용하기위한 것입니다. 이 프로젝트는 GNU C 라이브러리의 소스 코드 대부분을 성공적으로 전처리하는 데 사용되었습니다. 버전 1.2.5부터 Apple Objective C 라이브러리를 전처리 할 수도 있습니다.

http://www.anarres.org/projects/jcpp/


1
이것이 내 필요에 맞는지 잘 모르겠습니다. 내 코드는 Java로 작성되었습니다. 어쩌면 당신은 그들의 소스를 가져 와서 내 코드를 전처리하는 데 사용하도록 제안하고 있습니까?
jutky

2

정말 조건부 컴파일이 필요하고 Ant 를 사용하는 경우 코드를 필터링하고 검색 및 바꾸기를 수행 할 수 있습니다.

예 : http://weblogs.java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html

같은 방법으로 당신은, 예를 들어, 교체 필터 쓸 수 LOG.debug(...);와를 /*LOG.debug(...);*/. 이것은 if (LOG.isDebugEnabled()) { ... }동시에 더 간결하다는 것은 말할 것도없고 물건 보다 더 빨리 실행될 것 입니다.

Maven 을 사용하는 경우 여기에 설명 된 유사한 기능이 있습니다 .


2

Manifold 는 완전히 통합 된 Java 전처리기를 제공합니다 (빌드 단계 또는 생성 된 소스 없음). 조건부 컴파일만을 대상으로하며 C 스타일 지시문을 사용합니다.

매니 폴드의 자바 전 처리기


1

팩토리 패턴을 사용하여 클래스 구현간에 전환 하시겠습니까?

객체 생성 시간은 이제 문제가 될 수 없습니까? 장기간에 걸쳐 평균을 낼 때 소비 된 시간의 가장 큰 구성 요소는 이제 주 알고리즘에 있어야합니다. 그렇지 않습니까?

엄밀히 말하면, 달성하고자하는 일을 수행하기 위해 전처리 기가 실제로 필요하지는 않습니다. 물론 내가 제안한 것보다 귀하의 요구 사항을 충족시키는 다른 방법이있을 것입니다.


변경 사항은 매우 사소합니다. 요청 된 결과를 재 계산하는 대신 미리 알기 위해 일부 조건을 테스트하는 것과 같습니다. 따라서 함수 호출의 오버 헤드는 나에게 적합하지 않을 수 있습니다.
jutky

0
final static int appFlags = context.getApplicationInfo().flags;
final static boolean isDebug = (appFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.