行ごとにテキストファイルのコンテンツを繰り返します - ベストプラクティスはありますか? (vs. PMDのassignmentinoperand)
-
10-10-2019 - |
質問
テキストファイルを読み取ることを知っているいくつかのモジュールがあるJavaアプリケーションがあります。彼らはこのようなコードで非常に単純にそれを行います:
BufferedReader br = new BufferedReader(new FileReader(file));
String line = null;
while ((line = br.readLine()) != null)
{
... // do stuff to file here
}
走った PMD 私のプロジェクトで、Assignmentinoperand'違反 while (...)
ライン。
明白なもの以外のこのループを実行するより簡単な方法はありますか:
String line = br.readLine();
while (line != null)
{
... // do stuff to file here
line = br.readLine();
}
これはより良い練習と考えられていますか? (ただし、「複製」します line = br.readLine()
コード?)
解決
私は一般的に前者を好みます。私はしません 一般的 比較内の副作用のように、この特定の例は非常に一般的で便利なイディオムです。
(C#にはより良いオプションがあります:戻る方法 IEnumerable<string>
foreachで反復することができます。 Javaではそれほど良くありません。なぜなら、Loopの強化されたエンハンスの終わりに自動障害がないからです...そしてあなたは投げることができないからです IOException
イテレーターから、つまり、一方をもう片方にドロップイン交換することはできません。)
別の言い方をすれば、重複したラインの問題は、オペランドの問題の課題よりも私を悩ませます。私は一目でこのパターンを取り入れることに慣れています - 重複したラインバージョンを使用して、すべてが正しい場所にあることを確認する必要があります。それはおそらく他のものと同じくらい習慣ですが、問題だとは思いません。
他のヒント
私は古い投稿であることは知っていますが、私は同じ必要性がありました(ほぼ)、Apache CommonsのFileutilsのラインターターを使用してそれを解決します。彼らのJavadocから:
LineIterator it = FileUtils.lineIterator(file, "UTF-8");
try {
while (it.hasNext()) {
String line = it.nextLine();
// do something with line
}
} finally {
it.close();
}
ドキュメントを確認してください。http://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/lineiterator.html
のサポート ストリーム と ラムダス Java-8および リソースで試してください Java-7を使用すると、よりコンパクトな構文で必要なものをアカイティブにすることができます。
Path path = Paths.get("c:/users/aksel/aksel.txt");
try (Stream<String> lines = Files.lines(path)) {
lines.forEachOrdered(line->System.out.println(line));
} catch (IOException e) {
//error happened
}
私は日常的に使用します while((line = br.readLine()) != null)
構成...しかし、 最近、私はこの素敵な代替品を吸収しました:
BufferedReader br = new BufferedReader(new FileReader(file));
for (String line = br.readLine(); line != null; line = br.readLine()) {
... // do stuff to file here
}
これはまだ複製しています readLine()
コードを呼び出しますが、ロジックは明確です。
それ以外の場合は、私が使用します while(( ... ) ...)
コンストラクトは、ストリームからの読み取りです byte[]
配列...
byte[] buffer = new byte[size];
InputStream is = .....;
int len = 0;
while ((len = is.read(buffer)) >= 0) {
....
}
これは、以下を使用してfor loopに変換することもできます。
byte[] buffer = new byte[size];
InputStream is = .....;
for (int len = is.read(buffer); len >= 0; len = is.read(buffer)) {
....
}
ループの代替品を本当に好むかどうかはわかりません....しかし、それはあらゆるPMDツールを満たし、ロジックはまだ明確です。
ジョンの答えに基づいて、私はそれがファイルのイテレーターとして機能するデコレーターを作成するのに十分簡単であるべきだと思ったので、foreachループを使用できます。
public class BufferedReaderIterator implements Iterable<String> {
private BufferedReader r;
public BufferedReaderIterator(BufferedReader r) {
this.r = r;
}
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
@Override
public boolean hasNext() {
try {
r.mark(1);
if (r.read() < 0) {
return false;
}
r.reset();
return true;
} catch (IOException e) {
return false;
}
}
@Override
public String next() {
try {
return r.readLine();
} catch (IOException e) {
return null;
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
公正な警告:これにより、読み取り中に発生する可能性のあるiOExceptionsを抑制し、単に読み取りプロセスを停止します。イテレーターメソッドのセマンティクスが明確に定義されており、for-each構文を使用するために適合する必要があるため、ランタイムの例外を投げることなくJavaでこれを回避する方法があることは不明です。また、ここで複数のイテレーターを実行すると、奇妙な動作があります。だから、これが推奨されるかどうかはわかりません。
しかし、私はこれをテストしましたが、それは機能します。
とにかく、これを一種のデコレーターとして使用して、for-each構文の利点が得られます。
for(String line : new BufferedReaderIterator(br)){
// do some work
}
グーグルの グアバ図書館 静的方法を使用して、代替ソリューションを提供します charstreams.readlines(読み取り可能、ラインプロセッサu003CT>)) の実装で LineProcessor<T>
各行を処理するため。
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
CharStreams.readLines(br, new MyLineProcessorImpl());
} catch (IOException e) {
// handling io error ...
}
の体 while
ループはに配置されます LineProcessor<T>
実装。
class MyLineProcessorImpl implements LineProcessor<Object> {
@Override
public boolean processLine(String line) throws IOException {
if (// check if processing should continue) {
// do sth. with line
return true;
} else {
// stop processing
return false;
}
}
@Override
public Object getResult() {
// return a result based on processed lines if needed
return new Object();
}
}
次の選択肢が言及されていないことに少し驚いています:
while( true ) {
String line = br.readLine();
if ( line == null ) break;
... // do stuff to file here
}
Java 8の前には、その明確さがあり、繰り返しを必要としないため、それは私のお気に入りでした。 IMO、 break
副作用を備えた表現のより良いオプションです。しかし、それはまだイディオムの問題です。
assignmentinoperandはPMDの物議を醸すルールです。この規則の理由は、「これによりコードをより複雑で読みにくくすることができます」です(参照してください」(参照してください」 http://pmd.sourceforge.net/rules/controversial.html)
あなたが本当にそれをそのようにしたいなら、あなたはそのルールを無効にすることができます。私の側では前者が好きです。