2012-01-20 23 views
18

私は友人がJavaについてよく知らないJavaコードを書くのを手伝っていました。だから私は彼の目にはちょっと変わったことを簡単にやるためのヘルパー機能を書いていました。それらの1つは、OutputStreamに文字列を書き込む関数です。見てください:System.outは閉じられましたか?私はそれを再び開くことができますか?

public void write(String txt, OutputStream out) { 
    PrintWriter printer = new PrintWriter(out); 
    printer.print(txt); 
    printer.close(); 
} 

これで、どこでも簡単にさまざまな方法で書き込むことができます。たとえば、あなたはそれを行うことができます

(new StreamHelper()).write("Hello Test", System.out); 

は、私はその後System.out.println()はもうシェルには何も書き込まないことが分かったことを行います。だから私はおそらくprinter.close()も自動的に閉じてSystem.outと思うと私はこの機能が再び終了した後に私はそれを使用することができるようにそれを再アクティブ化するのだろうか。

私の前提は正しいですか? (ここに尋ねることなく私はどのように知りましたか)

write()関数の呼び出し後に、System.outを引き続き使用するにはどうすればよいですか?

このようなヘルパー機能を記述するのに良い方法はありますか?

+3

私のために便利になるかもしれませんしかし、あなたは次のように閉じ取得からのストリームを保護するためのファサードを書くことができますあなたは 'close()'の代わりに 'flush'を使うことができます。 –

+1

'write'メソッドを静的にして、'(新しいStreamHelper())。write(...) 'コールを避けることができます。 – adarshr

+2

@Stasクリリン:私はそれを試して、それは動作します。 – erikbwork

答えて

19

近いOutputStream年代のための一般的な契約:

ます。public void近い() がthrows IOExceptionこの出力ストリームを解放し、このストリームに関連するすべてのシステムリソースを閉じスローします。 closeの一般契約 は、それが出力ストリームを閉じるということです。閉鎖されたストリームは 出力操作を実行できず、は再オープンできません

PrintStreamさん

ます。public void close()ストリームを閉じます。これは、 ストリームをフラッシュし、次にを出力ストリームで閉じることによって行われます。

私はあなたを与えることができる唯一のアドバイスは、あなたがあなたのコードがどこか別の場所に作成されたリソースの閉鎖を委任していない、つまり、asymmetrical codeを書くべきではありませんということです。

あなたのケースでは、ラッパーストリームを閉じることは賢明かもしれませんが、他の場所で開かれているストリームを閉じているため、実際は使用しないでください。要するに

public void write(String txt, OutputStream out) { 
    PrintWriter printer = new PrintWriter(out); 
    printer.print(txt); 
    printer.flush(); 
    //it is very unpolite to close someone else's streams! 
    //printer.close(); 
} 

ああ、ところで、あなたはむしろwriteより、printに関数名を変更することもできます。

+0

私はそれが答えと問題の解決策を含んでいると思います。みんなのおかげでよろしく! – erikbwork

3

System.outはPrintStreamなので、上記のコードは文字通りSystem.out.printを呼び出すだけの利点はありません。これ以上書いていないのは、closeが、実際にはSystem.outに近いということです。

これがロギング用であれば、あなたの友人のためにlog4jを学んでもらうか、彼がそれを学ぶのを手伝ってください。 Log4jはファイルストリーム、標準出力などに同時に書き込む必要がある状況を処理します。

+2

かなりです。 System.outだけでなく他のストリームも使用できるという点で、抽象化の利点があります。 –

+2

ロギングなどの抽象化が実際に必要なユースケースを持っていない限り、それは無意味です。 –

3

入力がoutの場合は、System.outが選択されていて、閉じることはできません。

flush()コールが必要です。このwriteメソッドをSystem.out引数で呼び出すと、参照が同一になるので、==チェックを実行していることに注意してください。

public void write(String txt, OutputStream out) { 
    PrintWriter printer = new PrintWriter(out); 
    printer.print(txt); 
    printer.flush(); 

    if(out != System.out) { 
     printer.close(); 
    } 
} 

しかし、正直なところ、私はクロージングのための別の方法を維持するか、混乱を避けるために、このメソッドwriteAndCloseを呼び出します。

抽象化を維持したい場合(@Ursのヒント)、次のようにします。しかし、私はこの時点に、むしろオーバーエンジニアリング

public void write(String txt, OutputStream out) { 
    PrintWriter printer = new PrintWriter(out); 
    printer.print(txt); 
    printer.flush(); 
} 

public void close(OutputStream out) { 
    out.close(); 
} 
+0

元のソリューションが作成した抽象化を破ります。 –

2

が表示されないのは、ビューの呼び出し側の視点からこれを見てみましょう。

呼び出し元は、ある種のOutputStreamを持ち、write()というメソッドを呼び出します。コールが完了すると、呼び出し元はストリームが閉じられたことを検出します。

私の見解では、write()メソッドはprinter.close()を呼び出すべきではありません。後者は、呼び出し元によって提供されるストリームを閉じ、おそらく呼び出し元が期待するものではありません。

ストリームをフラッシュする必要がある場合は、flush()を使用できます。

2

Stur Kurilinが示唆するものを実行します。

一般に、ストリームは、ストリームを開いた/作成したパーティによって閉じられる必要があります。

あなたのメソッドでは、単にストリームをフラッシュします。不要になったときに開いた場所で閉じてください。

+0

+1私の名前を宣伝するため) –

9

他の人が言ったように、ストリームは開かれた場所で閉じられるべきです。

import java.io.FilterOutputStream; 
import java.io.IOException; 
import java.io.OutputStream; 

public class UnclosableOutputStream extends FilterOutputStream { 

    public UnclosableOutputStream(OutputStream out) { 
     super(out); 
    } 

    @Override 
    public void close() throws IOException { 
     out.flush(); 
    } 
} 

をし、このようにそれを使用します:

new StreamHelper().write("Hello Test", new UnclosableOutputStream(System.out)); 

は、テストシナリオなど

関連する問題