67

なぜassertキーワードがJavaであまり使われていないのか疑問に思いますか?使用されているのを見たことがほとんどありませんが、素晴らしいアイデアだと思います。私は確かに次の簡潔さを大いに好みます:

assert param != null : "Param cannot be null";

の冗長性に:

if (param == null) {
    throw new IllegalArgumentException("Param cannot be null");
}

私の疑いは、それらが十分に活用されていないということです。

  • 彼らは比較的遅く到着し(Java 1.4)、その時までに多くの人々がすでにJavaプログラミングスタイル/習慣を確立していました。
  • これらはデフォルトで実行時にオフになっています
4

11 に答える 11

64

assertions are, in theory, for testing invariants, assumptions that must be true in order for the code to complete properly.

The example shown is testing for valid input, which isn't a typical usage for an assertion because it is, generally, user supplied.

Assertions aren't generally used in production code because there is an overhead and it is assumed that situations where the invariants fail have been caught as coding errors during development and testing.

Your point about them coming "late" to java is also a reason why they aren't more widely seen.

Also, unit testing frameworks allow for some of the need for programmatic assertions to be external to the code being tested.

于 2008-11-18T14:45:16.243 に答える
57

It's an abuse of assertions to use them to test user input. Throwing an IllegalArgumentException on invalid input is more correct, as it allows the calling method to catch the exception, display the error, and do whatever it needs to (ask for input again, quit, whatever).

If that method is a private method inside one of your classes, the assertion is fine, because you are just trying to make sure you aren't accidentally passing it a null argument. You test with assertions on, and when you have tested all the paths through and not triggered the assertion, you can turn them off so that you aren't wasting resources on them. They are also useful just as comments. An assert at the start of a method is good documentation to maintainers that they should be following certain preconditions, and an assert at the end with a postcondition documents what the method should be doing. They can be just as useful as comments; moreso, because with assertions on, they actually TEST what they document.

Assertions are for testing/debugging, not error-checking, which is why they are off by default: to discourage people from using assertions to validate user input.

于 2008-11-18T15:03:12.587 に答える
18

From Programming with Assertions

By default, assertions are disabled at runtime. Two command-line switches allow you to selectively enable or disable assertions.

This means that if you don't have complete control over the run-time environment, you can't guarantee that the assertion code will even be called. Assertions are meant to be used in a test-environment, not for production code. You can't replace exception handling with assertions because if the user runs your application with assertions disabled (the default), all of your error handling code disappears.

于 2008-11-18T15:01:32.590 に答える
18

Joshua Bloch は、"Effective Java"で ("Check parameters for validation" トピックで) 提案しました (採用する単純なルールのようなものです)。パブリック メソッドについては、引数を検証し、無効であることが判明した場合は必要な例外をスローします。また、非パブリック メソッド (公開されておらず、ユーザーとしてその有効性を確認する必要があります) の場合は、代わりにアサーションを使用できます。

于 2008-11-18T18:21:25.667 に答える
9

@Don、アサーションがデフォルトでオフになっていることに不満を感じています。私もそうだったので、それらをインライン化するこの小さなjavacプラグインを作成しました(つまりif (!expr) throw Ex、このばかげたアサートバイトコードではなく、バイトコードを発行します.

Java コードのコンパイル中にクラスパスにfa.jarを含めると、その魔法が実行されてから通知されます

Note: %n assertions inlined.

@see http://smallwiki.unibe.ch/adriankuhn/javacompiler/forceassertionsまたは github https://github.com/akuhn/javacを参照

于 2009-03-20T13:14:05.060 に答える
2

アサーションは次の理由で役立ちます。

  • PROGRAMMING エラーを早期に発見
  • コードを使用してコードを文書化する

それらをコードの自己検証と考えてください。失敗した場合は、プログラムが壊れており、停止する必要があることを意味するはずです。単体テスト中は常にオンにしてください!

The Pragmatic Programmerでは、本番環境で実行することを推奨しています。

アサーションをオンのままにする

アサーションを使用して不可能を防止します。

アサーションは失敗すると AssertionError をスローするため、catch Exception によってキャッチされないことに注意してください。

于 2013-07-29T08:12:43.420 に答える
2

assert をわざわざ書いて、それを標準の if then 条件文に置き換える理由がよくわかりません。最初から条件を if として書いてみませんか?

アサートはテスト専用であり、2 つの副作用があります: 有効にすると、バイナリが大きくなり、パフォーマンスが低下します (これが、アサートをオフにできる理由です!)

条件の検証にアサートを使用しないでください。これは、アサートが有効/無効になると、実行時のアプリの動作が異なることを意味するためです。これは悪夢です!

于 2009-11-09T13:40:50.203 に答える
2

tl;dr

  • はい、意味のある本番環境でアサーション テストを使用します。
  • 必要に応じて、組み込み機能ではなく、他のライブラリ ( JUnitAssertJHamcrestassertなど) を使用してください。

このページの他の回答のほとんどは、「アサーションは通常、運用コードでは使用されません」という格言を押し付けています。ワープロやスプレッドシートなどの生産性アプリでは当てはまりますが、Java が非常に一般的に使用されるカスタム ビジネス アプリでは、アサーション-本番環境でのテストは非常に便利であり、一般的です。

プログラミングの世界の多くの格言と同様に、ある文脈では正しいと思われることは、誤解され、別の文脈では誤って適用されます。

生産性アプリ

「アサーションは通常、製品コードでは使用されない」というこの格言は、一般的ではありますが、正しくありません。

形式化されたアサーション テストは、 Microsoft WordなどのワードプロセッサやMicrosoft Excelなどのスプレッドシートなどのアプリで生まれました。これらのアプリは、ユーザーがキーストロークを行うたびに一連のアサーション テスト アサーションを呼び出す可能性があります。このような極端な繰り返しは、パフォーマンスに深刻な影響を与えました。そのため、配布が制限されているそのような製品のベータ版のみがアサーションを有効にしていました。したがって、格言。

ビジネスアプリ

対照的に、データ入力、データベース、またはその他のデータ処理用のビジネス指向アプリでは、本番環境でのアサーション テストの使用は非常に役立ちます。パフォーマンスへのわずかな影響により、非常に実用的で一般的なものになります.

ビジネス ルールのテスト

本番環境での実行時にビジネス ルールを検証することは完全に合理的であり、推奨されます。例えば:

  • 請求書に常に 1 つ以上の項目が必要な場合は、請求書の項目の数が 0 より大きいかどうかをテストするアサーションを記述します。
  • 製品名が少なくとも 3 文字以上でなければならない場合は、文字列の長さをテストするアサーションを記述します。
  • 現金元帳の残高を計算するとき、結果が決して負になることはあり得ないことがわかっているので、データまたはコードの欠陥を示す負の数をチェックしてください。

このようなテストは、本番環境のパフォーマンスに大きな影響を与えません。

実行条件

アプリが本番環境で実行されるときに、特定の条件が常に真であることをアプリが想定している場合は、それらの想定をアサーション テストとしてコードに記述します。

これらの条件がときどき失敗する可能性があると予想される場合は、アサーション テストを記述しないでください。おそらく、特定の例外をスローします。その後、可能な限り回復を試みます。

健全性チェック

本番環境での実行時の健全性チェックも完全に合理的であり、推奨されるべきです。真実でないとは想像もつかないいくつかの恣意的な条件をテストすることで、奇妙な出来事が発生した数え切れないほどの状況でベーコンを救うことができました。

たとえば、特定のライブラリでニッケル (0.05) をペニーに丸めるとニッケル (0.05) になることをテストしたことで、Apple がRosettaライブラリに出荷した浮動小数点技術の欠陥を最初に発見した人の 1 人になりました。 PowerPC から Intel への移行。そのような欠陥が一般に届くことは不可能に思えたでしょう。しかし驚くべきことに、この脆弱性は、元のベンダーである Transitive と Apple、そして Apple のベータ版でテストを行っていた早期アクセスの開発者の目に留まることはありませんでした。

(ちなみに、私は言及する必要があります…お金のために浮動小数点を使用しないでください、使用してBigDecimalください。)

フレームワークの選択

組み込み機能を使用するのではなく、assert別のアサーション フレームワークの使用を検討することをお勧めします。次のような複数のオプションがあります。

または独自のロール。プロジェクトで使用する小さなクラスを作成します。このようなもの。

package work.basil.example;

public class Assertions {
    static public void assertTrue ( Boolean booleanExpression , CharSequence message ) throws java.lang.AssertionError {
        if ( booleanExpression ) {
            // No code needed here.
        } else { // If booleanExpression is false rather than expected true, throw assertion error.
            // FIXME: Add logging.
            throw new java.lang.AssertionError( message.toString() );
        }
    }

}

使用例:

Assertions.assertTrue( 
    localTime.isBefore( LocalTime.NOON ) , 
    "The time-of-day is too late, after noon: " + localTime + ". Message # 816a2a26-2b95-45fa-9b0a-5d10884d819d." 
) ;

あなたの質問

それらが登場したのは比較的遅く (Java 1.4)、その頃には多くの人が Java プログラミングのスタイルや習慣をすでに確立していました。

はい、これは本当です。多くの人々は、Sun/JCP がアサーション テスト用に開発した API に失望しました。そのデザインは、既存のライブラリに比べて精彩を欠いていました。非常に多くの人が新しい API を無視し、既知のツール (サードパーティ ツール、または独自のミニ ライブラリを作成) を使い続けました。

これらはデフォルトで実行時にオフになっています.WHY OH WHY??

初期の頃、Java はパフォーマンス速度の低さで非難されていました。皮肉なことに、Java は急速に進化し、最高のパフォーマンス プラットフォームの 1 つになりました。しかし、悪いラップは臭い匂いのようにぶら下がっていました。そのため、Sun は、測定可能な方法でパフォーマンスに影響を与える可能性のあるものには、非常に慎重でした。したがって、この観点から、アサーション テストを無効にすることをデフォルトにすることは理にかなっています。

デフォルトで無効にするもう 1 つの理由は、新しいアサーション機能を追加する際に、Sun が単語をハイジャックしたという事実に関連していた可能性がありますassert。これは、以前は予約されていたキーワードではなく、Java 言語に加えられた数少ない変更の 1 つが必要でした。メソッド名assertは、多くのライブラリや多くの開発者が独自のコードで使用していました。この歴史的な移行に関する議論については、この古いドキュメント、Programming With Assertionsをお読みください。

于 2019-02-20T03:25:26.777 に答える
1

Assertions are very limited: You can only test boolean conditions and you need to write the code for a useful error message every time. Compare this to JUnit's assertEquals() which allows to generate a useful error message from the inputs and even show the two inputs side by side in the IDE in a JUnit runner.

Also, you can't search for assertions in any IDE I've seen so far but every IDE can search for method invocations.

于 2008-11-18T14:57:00.977 に答える
0

実際、彼らはJava1.4に到着しました。

主な問題は、 EclipseサーバーやJ2EEサーバーのようにJVMオプションを自分で直接管理しない環境でコーディングする場合です(どちらの場合もJVMオプションを変更できますが、どこを見つけるかを深く検索する必要があります)。実行可能)、使用が簡単(つまり、必要な労力が少ない)if、例外(または何も使用しない)があります。

于 2008-11-18T14:44:23.030 に答える
0

他の人が述べているように、アサーションはユーザー入力の検証には適していません。

冗長性が気になる場合は、私が書いたライブラリhttps://github.com/cowwoc/requirements.java/を確認することをお勧めします。非常に少ないコードを使用してこれらのチェックを表現できるようになり、ユーザーに代わってエラー メッセージを生成することさえできます。

requireThat("name", value).isNotNull();

アサーションの使用を主張する場合は、これも実行できます。

assertThat("name", value).isNotNull();

出力は次のようになります。

java.lang.NullPointerException: name may not be null
于 2017-04-06T17:28:23.867 に答える