1

次のコードをjavacでコンパイルする場合、コンパイラーはcodeInput.length()を1回だけ評価するのに十分賢いのでしょうか、それともイテレーター変数の影響を受ける評価を最初に置くことでより高速なプログラムを取得できるのでしょうか?

// edit: The first character must be an upper case letter, the next four must be 
// edit: numeric and there must be exactly five characters in total in a product
// edit: code.

for (int i = 1; i < 5; i++)
    if (codeInput.length() != 5 || codeInput.charAt(i) < '0' 
        || codeInput.charAt(i) > '9' || codeInput.charAt(0) < 'A'
        || codeInput.charAt(0) > 'Z')
        {if (verbose) System.out.println("Sorry, I don't understand! 
            Use product codes only."); return true;}
4

6 に答える 6

3

原則として; できる限り単純で明確なコードを書く必要があります。そうすれば、これはうまく機能します。多くの場合、パフォーマンスの問題は、コードをより明確にすることを思い付くことがはるかに重要です。あなたの例では、私はそれをこのように書きます。

static final Pattern CODE = Pattern.compile("[A-Z][0-9]{4}");

if (!CODE.matcher(codeInput).matches()) {
    if (verbose) 
        System.out.println("Sorry, I don't understand! Use product codes only.");
    return true;
}

これが少し遅い場合でも、IMHOを維持する方が明確で簡単です。


javac最適化はほとんど行われず、ほとんどすべてが実行時にJITによって実行されます。

次のコードをjavacでコンパイルする場合、コンパイラはcodeInput.length()を1回だけ評価するのに十分賢いでしょうか。

いいえ、でも、

または、イテレータ変数の影響を受ける評価を最初に配置することで、より高速なプログラムを取得できる可能性がありますか?

コードが十分に長く実行され、メソッドがインライン化されるとJITが起動し、ローカル変数が不要になるため、違いに気付くのとは異なります。

于 2013-01-02T09:30:29.293 に答える
2

最初の目標は、コードの単純さと読みやすさです。あなたが提示する問題と同じくらい単純な問題の場合、あなたはそれをパフォーマンスのボトルネックに変えるために本当にあなたの邪魔にならないようにしなければならないでしょう。文字列検証への最もクリーンで最も柔軟なアプローチは、正規表現です。

boolean valid = codeInput.matches("[A-Z][0-9]{4}");
if (!valid && verbose) 
   System.out.println("Sorry, I don't understand! Use product codes only.");
return !valid;

これから最後のパフォーマンスが本当に必要な場合は、正規表現をプリコンパイルできます。

static final Pattern productCodeRegex = Pattern.compile("[A-Z][0-9]{4}");
boolean validate(String codeInput) {
  boolean valid = productCodeRegex.matcher(codeInput).matches();
  ...
}
于 2013-01-02T10:01:59.020 に答える
1

codeInput.length()はい、各反復で評価されます。codeInputコンパイラーは、が最終的であるか、一度に1つのスレッドのみがアクセスできる場合、最適化を行うことができる場合があります。それ以外の場合codeInputは、現在のスレッドが気付かない別のスレッドによって変更される可能性があります。

したがってcodeInput.length()、ループの外側にシフトして、パフォーマンスの向上を利用するのはプログラマーの決定です。

于 2013-01-02T09:29:50.567 に答える
1

codeInput.length()コンパイラは、すべての反復で同じ値を返すかどうかを知ることができないため、すべての反復で評価するコードを作成する必要があります。クラスがどのように機能するかを知っているからです。しかし、コンパイラはそれを認識しておらず、codeInput変更を想定する必要があります(たとえば、の呼び出しによるcharAt())。

そうです:codeInput.length()一度評価して結果をローカル変数に割り当てることで、ある程度のパフォーマンスを得ることができます。

于 2013-01-02T09:30:30.397 に答える
1

ここで賢くなるのはコンパイラではなく、 JVMです。

最新のJVMにはすべてJIT(Just In Time)があります。これは、コードが外出先で最適化されることを意味します。

わざわざJavaでコードを最適化しようとせずに、正しいコードを記述してください。残りはJVMが自動的に行います。

特定のコードについては、GuavaCharMatcherを使用している場合は、ここで効果を上げることができます。

private static final CharMatcher PRODUCT_CHARS
    = CharMatcher.inRange('A', 'Z')
        .or(CharMatcher.inRange('a', 'z'))
        .or(CharMatcher.inRange('0', '9'))
        .precompute();

// In the verification method:
if (!(codeInput.length() == 5 && PRODUCT_CHARS.matchesAllOf(codeInput)))
    badProductCode();
于 2013-01-02T09:37:12.667 に答える
0

Markoの答えは、この質問でのプログラミングの取り組みにとって明らかに最良のものの1つです。

ただし、これを一般的な例として使用すると、スタイルと実践の問題として、そのようなより良い解決策がないコンテキスト(regexpやCharMatcherなど)に外挿することができます。ローカル変数を使用したメソッド呼び出しの結果。

これにより、ローカル変数に名前を付けることができるため、明確さが向上し、実行に最も論理的な場所に各単純なコードを配置できるようになります(また、JVMが本当に得意なことの1つ、つまりローカル変数を最適化できるようになります)利用方法)。

この変換されたバージョンでは、ループ内で繰り返しテストするのではなく、ループ外でfirstCharをテストしていることに気付くでしょう。.length()と同じです。私は最初に、これは論理的により正しいプログラミングであり(これがループ内で何度も繰り返される理由について他の読者を混乱させる)、次にパフォーマンスが向上することを主張します。

ループのこのようなコードの動きは、この単純な例のパフォーマンスに実質的に影響を与えませんが(5回の反復のカウントだけで、ループするライブラリを使用したより良いソリューションがあります)、一般的に、および他のコンテキストでは、これを次のように推奨しますベストプラクティス、より読みやすく、よりクリーンです(パフォーマンス指向でもあります)。

また、最初に長さをテストするので、.charAt(0)が存在することがわかっています。つまり、長さは> 0です。つまり、.charAt(0)reportError()をスローする代わりに、長さゼロの文字列を使用しますIndexOutOfBounds。これは、より単純な式を使用することでプログラミングロジックの優れた順序付けを可能にする方法のもう1つの例です。

このKIS(keep-it-simple)スタイルでは、これらのローカル変数を簡単に監視できるため、デバッグも容易になります。メンテナにとっても読みやすいと思います。

また、定数5を1箇所に限定すると、メンテナンスが容易になります。

public static final int expectedLength = 5;

..。

if ( codeInput.length() != expectedLength )
    return reportError ();

char firstChar = codeInput.charAt(0);
if ( firstChar < 'A' || firstChar > 'Z' )
    return reportError (); 

for (int i = 1; i < expectedLength; i++) {
    char nextChar = codeInput.charAt(i);
    if ( nextChar < '0' || nextChar > '9' )
        return reportError ();
}

..。

private static boolean reportError () {
    if (verbose) 
        System.out.println("Sorry, I don't understand!\nUse product codes only."); 
    return true;
}
于 2013-01-03T18:36:58.027 に答える