Java ラベル ステートメントの使用は避けるべきでしょうか?

StackOverflow https://stackoverflow.com/questions/46496

  •  09-06-2019
  •  | 
  •  

質問

今日、同僚に、ラベル ステートメントを使用して、作成した 2 つのネストされた for ループのフローを制御するようにコードをリファクタリングすることを提案されました。個人的にはプログラムの可読性が低下すると考えているため、これまで使用したことはありませんでした。ただし、議論が十分にしっかりしている場合は、それらを使用することについて考えを変えるつもりです。ラベルのステートメントに対する人々の意見は何ですか?

役に立ちましたか?

解決

2 つのループ (または switch ステートメントを含むループ) を飛び越えることができれば、多くのアルゴリズムをより簡単に表現できます。悪く思わないでください。一方で、過度に複雑な解決策を示している可能性があります。そこで、一歩下がって問題を見てください。

すべてのループに対して「単一入口、単一出口」アプローチを好む人もいます。つまり、ループの中断 (および続行) と早期復帰を完全に回避します。これにより、コードが重複する可能性があります。

私が絶対に避けたいのは、補助変数の導入です。状態内に制御フローを隠すと、混乱がさらに増します。

ラベル付きループを 2 つのメソッドに分割するのは難しい場合があります。おそらく例外は重すぎるでしょう。単一入口、単一出口アプローチを試してください。

他のヒント

ラベルは goto のようなものです。コードを高速化する場合にのみ、慎重に使用してください。 そして より重要なこと、より理解できること、

たとえば、6 レベルの深さの大きなループにいて、ループの残りを完了するのが無意味になるような条件に遭遇した場合、ループを早期に終了するために条件ステートメントに追加のトラップ ドアを 6 つ用意しても意味がありません。

ラベル (および goto) は悪ではありません。単に、人々がラベルを悪い方法で使用する場合があるだけです。ほとんどの場合、私たちは実際に、あなたや次のプログラマーにとって理解できるコードを書こうとしています。超高速にすることは二次的な関心事です (時期尚早な最適化に注意してください)。

ラベル (および goto) が誤用されると、コードが読みにくくなり、あなたと次の開発者に悲しみをもたらします。コンパイラは気にしません。

ラベルが必要になる機会はほとんどありませんが、めったに使用されないため、混乱を招く可能性があります。ただし、使用する必要がある場合は、使用してください。

ところで:これはコンパイルされて実行されます。

class MyFirstJavaProg {  
        public static void main(String args[]) {
           http://www.javacoffeebreak.com/java101/java101.html
           System.out.println("Hello World!");
        }
}

ラベルの代わりに何があるか知りたいです。これは結局のところ、「できるだけ早く戻る」か「帰還する」かという議論に帰着すると思います。「変数を使用して戻り値を保持し、最後にのみ返します。」

ネストされたループがある場合、ラベルは非常に標準的です。可読性が実際に低下する唯一の原因は、他の開発者がこれまでに見たことがなく、その意味を理解していない場合です。

Java コードでラベルが「実際に」使用されているのを見たことがありません。本当に入れ子になったループを分割したい場合は、メソッドをリファクタリングして、初期の return ステートメントが必要な動作を実行できるかどうかを確認してください。

技術的には、早期復帰とラベルの間に大きな違いはないと思います。しかし実際には、ほぼすべての Java 開発者が早期の復活を経験しており、それが何をするのかを知っています。多くの開発者は少なくともこのラベルに驚き、おそらく混乱するだろうと思います。

私は学校でシングルエントリー/シングルイグジットの正統性を教えられましたが、それ以来、コードを簡素化し明確にする方法として、早期リターンステートメントとループからの抜け出しを高く評価するようになりました。

私はいくつかの場所ではそれらを支持すると主張しますが、この例では特に有用であることがわかりました。


nextItem: for(CartItem item : user.getCart()) {

  nextCondition : for(PurchaseCondition cond : item.getConditions()) {
     if(!cond.check())
        continue nextItem;
     else
        continue nextCondition;

  }
  purchasedItems.add(item);
}

新しい for-each ループを使用すると、ラベルが非常に明確になると思います。

例えば:

sentence: for(Sentence sentence: paragraph) {
  for(String word: sentence) {
    // do something
    if(isDone()) {
      continue sentence;
    }
  }
}

新しい for-each でラベルを変数と同じにすることで、それが非常に明確になると思います。実際、おそらく Java は邪悪で、各変数に暗黙的なラベルを追加する必要があるでしょう。

素数を見つけるための Sieve メソッドの実装に Java ラベル付きループを使用しました (プロジェクトのオイラー数学問題の 1 つに対して実行しました)。これにより、ネストされたループと比較して 10 倍高速になりました。たとえば、if(特定の条件) は外側のループに戻ります。

private static void testByFactoring() {
    primes: for (int ctr = 0; ctr < m_toFactor.length; ctr++) {
        int toTest = m_toFactor[ctr];
        for (int ctr2 = 0; ctr2 < m_divisors.length; ctr2++) {
            // max (int) Math.sqrt(m_numberToTest) + 1 iterations
            if (toTest != m_divisors[ctr2]
                        && toTest % m_divisors[ctr2] == 0) {
                continue primes; 
            }
        } // end of the divisor loop
    } // end of primes loop
} // method

C++ プログラマに、ラベル付きループがいかに悪いかを尋ねたところ、ラベル付きループは慎重に使用するが、場合によっては便利であると彼は言いました。たとえば、ネストされたループが 3 つあり、特定の条件下で最も外側のループに戻りたい場合です。

したがって、それらにはそれぞれの用途があり、それは解決しようとしていた問題によって異なります。

コード内でラベルを使用することはありません。ガードを作成して初期化することを好みます ヌル またはその他の異常な値。このガードは多くの場合、結果オブジェクトです。私の同僚がラベルを使用しているのを見たことがありませんし、リポジトリでもラベルを見つけませんでした。それは実際のコーディングのスタイルによって異なります。私の意見では、ラベルは一般的な構造ではなく、通常 Java では使用されないため、ラベルを使用すると可読性が低下すると思います。

はい、ラベルを使用する特別な理由がない限り、ラベルの使用は避けるべきです (アルゴリズムの実装を簡素化する例が適切です)。そのような場合は、後から誰かが現れて「コードを改善する」とか「コードの臭いを取り除く」という概念からコードをめちゃくちゃにしないように、その背後にある理由を説明する十分なコメントやその他のドキュメントを追加することをお勧めします。他の潜在的なBSの言い訳。

私はこの種の質問を、いつ三項 if を使用するべきか、あるいは使用すべきでないかを決定することに等しいと考えています。主な根拠は、それが可読性を妨げる可能性があり、プログラマーが合理的な方法で名前を付けることに細心の注意を払っていない限り、ラベルなどの規則を使用すると事態がさら​​に悪化する可能性があるということです。「nextCondition」と「nextItem」を使用する例では、ラベル名に「loop1」と「loop2」が使用されていたとします。

個人的にラベルは、Assembly や BASIC、その他の同様に制限された言語を除けば、私にとってあまり意味をなさない機能の 1 つです。Java には、より従来型/通常のループおよび制御構造が多数あります。

ラベルは、通常のセットアップ、演習、検証フェーズを分離し、関連するステートメントをグループ化するために、テストで役立つことがあります。たとえば、BDD 用語を使用すると、次のようになります。

@Test
public void should_Clear_Cached_Element() throws Exception {
    given: {
        elementStream = defaultStream();
        elementStream.readElement();
        Assume.assumeNotNull(elementStream.lastRead());
    }
    when:
        elementStream.clearLast();
    then:
        assertThat(elementStream.lastRead()).isEmpty();
}

書式設定の選択はさまざまですが、中心的な考え方は、この場合、コメントよりもラベルのほうが、テストを構成する論理セクション間の顕著な区別を提供するということです。私は思います スポック ライブラリは、まさにこの機能に基づいてテスト フェーズを宣言するだけで構築されます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top