web-dev-qa-db-ja.com

#ifdef #ifndef in Java

C++の#ifdef #ifndefのようなJavaのようなコンパイル時の条件を作成する方法があるかどうか疑問です。

私の問題は、Javaで記述されたアルゴリズムを使用していることと、そのアルゴリズムの実行時間が異なることです。そのため、各改善を使用するときにどれだけの時間を節約できるかを測定したいと思います。

現在、実行時に改善すべきものとそうでないものを決定するために使用されるブール変数のセットがあります。しかし、これらの変数をテストすることでさえ、総実行時間に影響を与えます。

そこで、コンパイル時にプログラムのどの部分をコンパイルして使用するかを決定する方法を見つけたいと思います。

誰かがJavaでそれを行う方法を知っていますか?あるいは、そのような方法がないことを誰かが知っているかもしれません(それも有用です)。

102
jutky
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コンパイラーによって評価されます。このためのオーバーヘッドは無視できます。

120
Mark Thornton

javacは、到達不能のコンパイル済みコードを出力しません。 #defineの定数値に設定された最終変数と、#ifdefの通常のifステートメントを使用します。

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は次の出力を提供し、2つのパスのうち1つだけがコンパイルされたことを示します(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
43
Phil Ross

私は解決策を見つけたと思う、それははるかに簡単です。
「最終」修飾子でブール変数を定義すると、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++;
    }
11
jutky

使用したことはありませんが、これは存在します

JCPPは完全な、準拠した、スタンドアロンの、純粋なJava Cプリプロセッサの実装です。これは、CスタイルのコンパイラをJava = sablecc、antlr、JLex、CUPなどのツールを使用します。このプロジェクトは、GNU Cライブラリのバージョン1.2.5以降のソースコードの多くを正常に前処理するために使用されています。 、Apple Objective Cライブラリ。

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

2
Tom

本当に条件付きコンパイルが必要で、Antを使用する場合は、コードをフィルター処理して、検索と置換を実行できる場合があります。

例: http://weblogs.Java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html

同じ方法で、たとえば、LOG.debug(...);/*LOG.debug(...);*/に置き換えるフィルターを作成できます。これは、同時により簡潔であることは言うまでもなく、if (LOG.isDebugEnabled()) { ... }のものよりも高速に実行されます。

Mavenを使用する場合、here

2
rustyx

Manifold は、完全に統合されたJavaプリプロセッサ(ビルドステップまたは生成されたソースなし)を提供します。条件付きコンパイルのみを対象とし、Cスタイルのディレクティブを使用します。

Manifold's Java Preprocessor

1
Scott

Factoryパターンを使用して、クラスの実装を切り替えますか?

オブジェクトの作成時間は今では気になりませんか?長い実行期間にわたって平均すると、費やされる時間の最大の要素はメインアルゴリズムにあるはずです。

厳密に言えば、あなたが達成しようとしていることをするのにプリプロセッサは本当に必要ありません。もちろん、私が提案したもの以外にも、おそらく他の方法で要件を満たすことができます。

1
jldupont
final static int appFlags = context.getApplicationInfo().flags;
final static boolean isDebug = (appFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0
0
alicanbatur