このコードは、防御プログラミングのために他にどのように最適化できますか?
-
04-10-2019 - |
質問
私のデータ構造プロジェクトの場合、目標は、アーティスト、タイトル、歌詞が明確にマークされた10000以上の曲を含む提供されたファイルを読むことです。各曲は、1つの二重引用符でラインで区切られています。テキストファイルを解析するためにこのコードを作成しましたが、実行時間は3秒弱で機能します
422K行のテキストをお読みください
歌オブジェクトを作成します
その歌をArrayListに追加します
私が書いた解析コードは次のとおりです。
if (songSource.canRead()) { //checks to see if file is valid to read
readIn= new Scanner(songSource);
while (readIn.hasNextLine()) {
do {
readToken= readIn.nextLine();
if (readToken.startsWith("ARTIST=\"")) {
artist= readToken.split("\"")[1];
}
if (readToken.startsWith("TITLE=\"")) {
title= readToken.split("\"")[1];
}
if (readToken.startsWith("LYRICS=\"")) {
lyrics= readToken.split("\"")[1];
} else {
lyrics+= "\n"+readToken;
}//end individual song if block
} while (!readToken.startsWith("\"")); //end inner while loop
songList.add(new Song(artist, title, lyrics));
}//end while not EOF
} //end if file can be read
私はこのプロジェクトのコードについてアルゴリズム教授にイントロと話していましたが、彼は、他の人が提供するデータの矛盾を可能にするために、私のコードでより防御的になろうとするべきだと述べました。もともと私はアーティスト、タイトル、歌詞のフィールドの間でif/elseブロックを使用していましたが、彼の提案では、IFステートメントのシーケンシャルに変更されました。彼のポイントを見ることができますが、このコードの例を使用して、どうすれば入力の矛盾を許可することをより防御的にすることができますか?
解決
入力が完璧であると仮定しています。あなたのアプリケーションが現在セットアップされている方法を見ると、あなたのアルゴリズムの迅速な読み取りに基づいて、データは次のようになります
ARTIST="John"
TITLE="HELLO WORLD"
LYRICS="Sing Song All night long"
"
しかし、ケースを考慮してください
ARTIST="John"
TITLE="HELLO WORLD"
LYRICS="Sing Song All night long"
"
ARTIST="Peter"
LYRICS="Sing Song All night long"
"
あなたのアルゴリズムに基づいて、あなたは今、次のように特徴付けられる2曲を持っています
songList = { Song("JOHN", "HELLO WORLD", "Sing Song All night long"),
Song("Peter", "HELLO WORLD", "Sing Song All night long") }
現在のアルゴリズムを使用すると、アーティストとタイトルが公開され、定義されていなくても2番目の曲に表示されます。 3つの変数をリセットする必要があります。
他の人では、完全なラインを歌詞に捨てているだけです。もしあなたがすでに歌詞を引き出していたなら、あなたは今それを無効にしています。テストケース
ARTIST="John"
LYRICS="Sing Song All night long"
TILET="HELLO WORLD"
"
このレコードをエラー状態に送信することを検討してください。したがって、バッチ読み取りが完了すると、エラーレポートを生成して固定できます。
また、アーティストが読まれた後にのみEOFを考慮します。アーティストの読み取り中にEOFが発生し、ファイルが終了しない場合はどうなりますか。 ()
他のヒント
例:
artist= readToken.split("\"")[1];
と
String[] parts = readToken.split("\"");
if(parts.length >= 2) artist = parts[1];
else continue;
その他の変更には次のものが含まれます。
- ローカル変数をリセットします(したがって、最初の曲の後にアーティストが提供されていない場合、曲のために誤って間違ったアーティストを取得しないでください)
- データが欠落している場合はどうすればよいですか?曲を曲リストに追加したいですか?
現実の世界では、データの整合性に関していくつかの保証があります。ユーザーの入力(STDINまたはファイルから)を扱う場合、注意が必要な問題をユーザーに通知するためのプロジェクトを定義したパラダイムがあります。
たとえば、コンパイラコンパイルコードまたはスクリプトを実行するシェルが矛盾に遭遇する場合、停止して、「^」シンボルを使用して問題の位置を示す2番目の行の矛盾を含む行を印刷する可能性があります。
だからここに自問するためのいくつかの基本的な質問があります:
1.すべてのラインがすべてのフィールドを含めることが保証されていますか?
2.フィールドの順序は保証されていますか?
これらが入力契約の条件であり、違反されている場合は、行を無視/報告する必要があります。それらが入力の条件でない場合、あなたはそれを処理する必要があります..あなたは現在そうしません。
ここでジェイソンが欠けていることがいくつかあります。
if/elseは問題なく、ロジックは変わらないと思います。ただし、変数の範囲を可能な限り制限する必要があります。アーティスト、タイトルなどをWhileループ内で宣言することにより、それらはnull(または何でも)に初期化されるため、エントリがアーティストに欠落している場合、最後のエントリの値は得られません。
また、タイトル、アーティストなどが見積もりがある場合はどうなりますか?それはどのように処理されますか?複数の行のように見える歌詞はどうですか?
未知のフィールドがある場合はどうなりますか?それは歌詞の終わりに追加されますが、それは正しくないように見えます。歌詞フィールドが見つかった場合にのみ、あなたがそれに加えてください。歌詞の場合、「null」から始まります。
対処できるいくつかの問題は次のとおりです。
あなたのコードは、(たとえば)「アーティスト」、「=」のサインなどの周りにはありません。
コードは、キーワードがすべてのキャップにあると想定しています。誰かが小文字や混合ケースを使用できます。
あなたのコードは、で始まらない行が
keyword=\"
曲の歌詞の続きです。しかし、ユーザーが入力した場合はどうなりますかARTOST="Sting"
?または、ユーザーがアーティスト名に2行を使用しようとした場合はどうなりますか?
最後に、私はこの場合、「else」を「if」に置き換えると確信していません もっている コードの堅牢性に違いをもたらしました。
例外を処理します(スキャナーは、無効な文字のinputmismatchExceptionをスローできると思います)。
のように見えます do { } while (...)
ファイルが不適切であり、ファイルの最後に到達すると、際限なくループできます。
何も防ぎません artist
また title
空から。