109

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

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

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

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

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

4

9 に答える 9

129
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 コンパイラーによって評価されます。このためのオーバーヘッドはごくわずかです。

于 2009-11-28T21:50:48.013 に答える
46

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次の出力が得られます。これは、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
于 2009-11-28T21:49:44.220 に答える
12

私は解決策を見つけたと思います。それははるかに簡単です。
「final」修飾子を使用してブール変数を定義すると、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++;
    }
于 2009-11-28T22:16:08.390 に答える
2

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

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

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

Mavenを使用する場合は、ここで説明されている同様の機能があります。

于 2012-07-13T11:01:31.257 に答える
2

使ったことはないが、これはある

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

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

于 2009-11-28T21:40:53.890 に答える
1

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

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

厳密に言えば、目的を達成するためにプリプロセッサは必要ありません。もちろん、私が提案した方法以外にも、あなたの要件を満たす方法は他にもあるでしょう。

于 2009-11-28T21:41:36.723 に答える
0
final static int appFlags = context.getApplicationInfo().flags;
final static boolean isDebug = (appFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0
于 2015-09-21T12:45:22.290 に答える