ほとんどすべての学生が最初にプログラムを書くためにJavaを学ぶためにあるのHello Worldも使用されているのSystem.out.println()学校は、単に持っていたとき、私は、例外午前出力の「Hello World」へのこの声明このステートメントを使用すると、この文の後ろの原則を探求していないログを印刷する必要性を検討する際、通常、それらを利用するため、我々は彼らの原則を見に来ます。
System.out.println()標準I /本この概念でのUnix、即ち、標準的なプログラムからのすべての入力はできるが、「単一のストリームプログラムが使用する」にO、標準I / Oを参照して使用さを提供する能力の範疇に属し入力は、それはすべての出力を標準出力に送信することができ、任意のエラーメッセージが標準エラーに送信することができます。私たちは簡単に一緒にプログラムを置くことができ、一つのプログラムの標準出力を別のプログラムの標準入力になることができます。標準I / Oのセンスがあることです。
プログラムは、一般的に、コマンドラインで実行すると、コマンドライン環境とユーザーとの対話の下でされているので実際には、標準では、I / O、直感的に、というI / Oからのコマンドラインを理解することができます。ストリームにより、コンソールを通じて、標準的な方法:だからJavaプラットフォームは、対話と手順について説明する2つの方法を提供します。
標準的なフローがあり、オペレーティングシステムの機能の多くです。デフォルトでは、標準入力ストリームは、表示装置(ディスプレイ)、キーボード及び出力から読み出されます。同時に、ファイルまたはアプリケーションのI / Oへの入力と出力との間の標準的なフローが、これら二つの特徴が決定され、コマンドライン・インタプリタではなく、プログラムでサポート。
Javaプラットフォームは、3つの標準のストリームをサポートしています。
- System.inにより得られた標準入力、
- System.outにより得られた標準出力、
- System.errにして得られた標準誤差、
これらのオブジェクトは、事前に定義されており、手動開放を必要としません。また、エラー情報を読みながら、標準出力(標準出力)、および標準誤差(標準誤差)の出力は、ユーザーがファイルに正常に出力できることをエラー出力を提供することの利点を使用しています。
ここでは詳細にこれらの規格の流れを説明することです。
1.標準出力
1.1クラス構造
それはJavaの文です共通のSystem.out.printlnを()、と言わざるを得ない標準出力になると、はい、それはプログラム(stdout)に渡すことができるのはSystem.out印刷パラメータ。私たちは、ビューの三つの部分のポイントに分割することができます:
システム
これは以下のように、主な役割は、最終的なパッケージjava.langのクラスです。
- インフラストラクチャは、標準入力、標準出力、およびエラー出力ストリーム等を提供します。
- アクセス外部プロパティと環境変数を定義したために、
- これは、ファイルとライブラリをロードするための方法を提供します。
- これは、配列の内容の一部をコピーする簡単な方法を提供します。
でる
これは、静的メンバSystem]フィールド、PrintStream型のクラスです。そのアクセス識別子は、それが起動時にインスタンス化され、標準出力コンソールのホストに関連付けられており、ストリームは自動的にインスタンス化し、データを受け入れる準備ができた後、開いていることを意味し、公共の最終です。
println
これは、のPrintStreamの方法で、コンテンツがコンソールに出力することができます。
ここでは、オンラインクラス図の直接の盗難は、より明確な構造を確認するために結合します。
クラス構造を持つ、私たちはのSystem.outの他の操作のいくつかを見てみましょう。
1.2のSystem.outのPrintWriterに変換
System.outはPrintStreamをOutputStreamのあるPrintStreamを、です。PrintWriterのは、コンストラクタの引数として許容可能なOutputStreamを持っています。だから、あなたはのPrintWriterにはSystem.outを変換するために、コンストラクタを使用することができます。
パブリック クラスChangeSystemOut { 公共 静的 ボイドメイン(文字列[]引数){ のPrintWriterアウト = 新規のPrintWriter(のSystem.out、真)。 out.printlnを( "こんにちは、世界" ); } }
PrintWriter機能は、この後のPrintWriterここでコンストラクタを使用する2つのパラメータをパッケージングを使用することができ、自動クリア機能を開くように第2のパラメータは、trueに設定され、出力は、そうでなければ見えないかもしれません。
1.3出力のリダイレクト
うちのSystem.outオブジェクトを手動で指定することです。デフォルトでは、Java Runtime Environmentの起動時に初期化されます、そして、実行時に実際のオブジェクトを変更することができます。次の例では、出力がファイルにリダイレクトされるよう私たちは、setOut法による出力をリダイレクトすることができます:
パブリック クラス取換え{ 公共の 静的な 無効メイン(文字列の引数[]){ しようと{ (System.setOut 新しい PrintStreamを(新しいのFileOutputStream( "log.txtとの" ))); System.out.println(「今出力がリダイレクトされました!」); } キャッチ(例外e){} } }
そこに大量の出力があり、出力が速すぎて、彼らが読んでいないことを、画面のスクロールに表示されると、出力は非常に便利になりリダイレクトします。
1.4のSystem.out.printlnのパフォーマンス分析
我々はすべて知っているように、するSystem.out.println性能は、なぜ良くないのですか?、これはで日/ OracleのJDKで達成される>書き込み()+改行() - >印刷 - のprintln:私たちは、その呼び出しシーケンスを見ることができます。書き込み()と改行()メソッドが含まれている場合同期ブロック同期方法は、わずかなオーバーヘッドになり、それはまた、キャラクタの性能がバッファとプリントに追加される影響しました。
有文献表明,运行多个System.out.println并记录时间,执行时间会按比例增加。当打印超过50个字符并打印超过50,000行时,性能下降明显。
当然虽然System.out.println()性能不好,但是还是取决我们的使用场景,如果是写写demo学习则直接使用好了,因为是Java原生支持的特性,所以不需要引入任何依赖,这是其最大的好处吧。当然,在我们工作中开发商用软件,那就最好不要用System.out.println了,这就不仅仅是因为性能问题了。
1.5 System.out.println和通用日志组件的对比
为了方便,我们可能常常会直接使用System.out.println()输出日志,但是既然用System.out输出日志这么方便,那又为什么还需要那些通用日志组件(如log4j)呢?System.out.println()又存在什么问题?如下是一些常见的总结:
- 灵活性:像log4j这一类的通用组件提供了多种日志级别,这样就可以通过不同级别相应地分隔日志信息。例如,X消息只能在PRODUCTION级别打印,Y消息应打印在ERROR级别打印等,详细的级别定义这里就不再总结了。
- 可重构性:log4j只需一个参数更改即可关闭所有日志记录。
- 可维护性:想象一下,如果我们有数百个System.out.println散落在应用程序的各个角落,那将会使程序变得难以维护。
- 粒度:在应用程序中,每个类都可以有不同的记录器并相应地进行控制。
- 实用性:在System.out中重定向消息的选项比较少(指向文件、指向程序),但是像log4j之类的组件,其提供了更多的重定向选择,我们甚至可以重定向到自定义的输出选项。
所以呢如果我们只是正在编写一个小demo,只是为了实验/学习目的那么使用System.out.println是很方便的。但是当我们要开发软件时,我们就应该使用通用的日志组件比如log4j等。
2. 标准输入、标准错误
前面我们着重学习了一下标准输出,这里再总结一下它的兄弟:标准输入和标准错误。
标准输入和标准输入刚好相反,是用来从标准输入(一般是键盘)设备获取输入的。而标准错误则是通过PrintStream将错误信息打印到标准错误输出流中,在我们使用比如eclipse这种IDE时就可以看出它和标准输出的区别。看一个简单例子:
public class InOutErr { public static void main(String args[]) { try { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String filename = reader.readLine(); InputStream input = new FileInputStream(filename); System.out.println("File opened..."); } catch (IOException e){ System.err.println("Where is that file?"); } } }
启动程序之后会阻塞,等待输入文件名称,随意输入,如果找不到对应文件,就会输出错误日志,可以看一下结果,err的打印是红色的。
同样,标准输入和标准错误也可以进行重定向,可以通过System提供的一些静态方法完成重定向:
- setIn(InputStream)
- setOut(PrintStream)
- setErr(PrintStream)
这里是一个简单例子演示这些方法的使用:
public class Redirecting { public static void main(String[] args) throws IOException{ PrintStream console = System.out; BufferedInputStream in = new BufferedInputStream(new FileInputStream("pom.xml")); PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream("test.out"))); System.setIn(in); System.setOut(out); System.setErr(out); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String s; while((s = br.readLine()) != null){ System.out.println(s); } out.close(); // Remember this! System.setOut(console); } }
这个例子将标准输入重定向到文件上,并将标准输出和标准错误重定向到另一个文件上。注意,它在程序开头处存储了对最初的System.out对象的引用,并且在结尾处将系统输出恢复到了该对象上。
I/O重定向操纵的是字节流,而不是字符流,所以这里使用的是InputStream和OutputStream,而不是Reader和Writer。
3. 标准输入和输出的区别
标准输入和输出除了一个是输入,一个是输出,还有使用上的一些区别。
由于某些历史原因,标准流属于字节流,System.out和System.err其实是PrintStream类型。虽然是字节流,但是PrintStream利用一个内部字符流对象来字符流的许多特性。
相对标准输出而言System.in就只是一个单纯的字节流了,没有包含内部的字符流对象。如果要像字符流一样使用标准输入则需要通过InputStreamReader将其包装一下了:
InputStreamReader cin = new InputStreamReader(System.in);
标准输出和标准输入在这一点上的区别也可从两者的使用上看出来,以我们最常用的在控制台打印一条语句和从控制台接收键盘输入为例:
// 打印日志
System.out.println("");
// 接收标准输入
Scanner scan = new Scanner(System.in);
前者直接使用的是字符流的特性,后者则通过了一个Scanner进行包装。
4. 总结
- Java平台提供了三种标准流,分别是System.in(标准输入)、System.out(标准输出)、System.err(标准错误),我们常用的System.out.println()就是属于标准输出。
- System是java.lang包中的一个final类,out则是System类的一个静态成员,其类型为PrintStream,println()则是PrintStream的一个方法,可以输出内容到控制台。
- 标准流属于字节流,System.out和System.err其实是PrintStream类型,但是具有许多字符流的特性,而System.in就只是一个单纯的字节流。
- 标准流都可以进行重定向。
- System.out.println()性能并不好,但是平时学习使用是不影响的。
- 在项目中尽量不要使用System.out.println()输出日志,而应该使用更通用的日志组件来完成日志打印的任务。