【Java】深入剖析Java输入输出的那些细节
前言
無(wú)論是新手入門的命令行輸入輸出,還是說(shuō)OJ的讀入和輸出,離不開(kāi)基本的IO操作。
但Java本身由于純粹的面向?qū)ο?#xff0c;輸入輸出不方便,所以我們倒不妨探討一番。
其實(shí)輸入輸出真實(shí)是所有學(xué)Java的入門者一定要先去學(xué)的,但用的越多越能深入地感受到輸入輸出或多或少的小問(wèn)題。正所謂“養(yǎng)兵千日,用兵一時(shí)”,想要關(guān)鍵時(shí)刻一針見(jiàn)血,就必須在平時(shí)做好準(zhǔn)備。
Are you ready? OK ~ 那今天我們就來(lái)聊聊,我們?nèi)绾斡煤肑ava的輸入輸出。
看看Python
這叫輸入:
n=input()可以用eval()將輸入類型轉(zhuǎn)換成數(shù)值類型,用int()轉(zhuǎn)換成整數(shù)類型……
如下:
這叫輸出:
print(n)看看C++
cin可以輸入:
cin>>n;輸入還可以用scanf(),效率更高。
cout可以輸出:
cout<<n;輸出還可以用printf(),效率更高。
Java輸出篇
為什么先談?shì)敵瞿?#xff1f;
顯然因?yàn)楹?jiǎn)單啊。
普通輸出流有三種輸出方式:
第一種是不換行輸出:
int n = 1; System.out.print(n);第二種是換行輸出:
System.out.println(n);第三種是格式化輸出:
System.out.printf("%d", n);還有錯(cuò)誤輸出流,與上述內(nèi)容類似:
第一種是不換行輸出:
System.err.print(n);第二種是換行輸出:
System.err.println(n);第三種是格式化輸出:
System.err.printf("%d", n);Java輸出的一些問(wèn)題
異常是err錯(cuò)誤流,普通輸出是out普通輸出流,可能會(huì)在IDE里由于線程的問(wèn)題而混合在一起。
根據(jù)下面的源碼(java.lang.System),可知分別是InputStream、PrintStream對(duì)象,err流和out流是同一個(gè)類的不同對(duì)象。 public static final InputStream in;public static final PrintStream out;public static final PrintStream err;`
對(duì)于第五條,說(shuō)明一下。我們先寫一個(gè)測(cè)試類,打一下時(shí)間戳:
public class PrintTest {public static void main(String[] args) {int[] array = new int[100000];long time1 = System.currentTimeMillis();for (int i = 0; i < array.length-1; i++) {System.out.print(array[i] + " ");}System.out.println(array[array.length-1]);long time2 = System.currentTimeMillis();StringBuilder builder = new StringBuilder();for (int i = 0; i < array.length; i++) {builder.append(array[i]).append(" ");}System.out.println(builder.toString().trim());long time3 = System.currentTimeMillis();System.out.println("策略1的輸出時(shí)間:" + (time2-time1));System.out.println("策略2的輸出時(shí)間:" + (time3-time2));} }除去上面的兩行輸出,會(huì)打印:
策略1的輸出時(shí)間:330
策略2的輸出時(shí)間:10
顯然,用StringBuilder而不是直接一次接一次的System.out.print(),是正解啦。
Java輸入篇
記得在學(xué)校剛學(xué)的時(shí)候,第一節(jié)課老師就讓大家寫一下輸入輸出語(yǔ)句,輸出還好,輸入就不行了,很多同學(xué)不會(huì)寫。其實(shí)我也是在學(xué)了很多語(yǔ)法以后才學(xué)會(huì)的輸入啦,下面就來(lái)說(shuō)一說(shuō)吧。
其實(shí)對(duì)初學(xué)者的一個(gè)困難就是輸出可以不必import,但輸入則不然,需要import java.io.*,或者import java.util.Scanner,可能不那么容易直接理解。
一般比較“出名”的處理方式是java.util.Scanner,這倒確實(shí)。
Scanner類可以直接讀取一下類型的對(duì)象:
- public String next() → 讀取下一個(gè)字符串(默認(rèn)分隔符為Space or Tab or Enter)
- public String next?(String pattern) → 讀取下一個(gè)字符串(匹配到的串符合指定的正則表達(dá)式)
- public String next?(Pattern pattern) → 讀取下一個(gè)字符串(匹配到的串符合指定的正則表達(dá)式)
- public BigDecimal nextBigDecimal() → 讀取下一個(gè)高精小數(shù)(默認(rèn)十進(jìn)制)
- public BigInteger nextBigInteger() → 讀取下一個(gè)高精整數(shù)(默認(rèn)十進(jìn)制)
- public BigInteger nextBigInteger?(int radix) → 讀取下一個(gè)高精整數(shù)(指定進(jìn)制)
- public boolean nextBoolean() → 讀取下一個(gè)布爾值
- public byte nextByte() → 讀取下一個(gè)byte整型數(shù)值(超容會(huì)報(bào)錯(cuò),默認(rèn)十進(jìn)制)
- public byte nextByte?(int radix) → 讀取下一個(gè)byte整型數(shù)值(超容會(huì)報(bào)錯(cuò),指定進(jìn)制)
- public double nextDouble() → 讀取下一個(gè)雙精度浮點(diǎn)數(shù)值(默認(rèn)十進(jìn)制)
- public float nextFloat() → 讀取下一個(gè)單精度浮點(diǎn)數(shù)值(默認(rèn)十進(jìn)制)
- public int nextInt() → 讀取下一個(gè)int整型數(shù)值(超容會(huì)報(bào)錯(cuò),默認(rèn)十進(jìn)制)
- public int nextInt?(int radix) → 讀取下一個(gè)int整型數(shù)值(超容會(huì)報(bào)錯(cuò),指定進(jìn)制)
- public String nextLine() → 讀取下一行內(nèi)容以字符串類型返回(分隔符為Enter)
- public long nextLong() → 讀取下一個(gè)long整型數(shù)值(超容會(huì)報(bào)錯(cuò),默認(rèn)十進(jìn)制)
- public long nextLong?(int radix) → 讀取下一個(gè)long整型數(shù)值(超容會(huì)報(bào)錯(cuò),指定進(jìn)制)
- public short nextShort() → 讀取下一個(gè)short整型數(shù)值(超容會(huì)報(bào)錯(cuò),默認(rèn)十進(jìn)制)
- public short nextShort?(int radix) → 讀取下一個(gè)short整型數(shù)值(超容會(huì)報(bào)錯(cuò),指定進(jìn)制)
看吧,確實(shí)“全能”,不過(guò)我們?cè)诳吹絊canner便捷的同時(shí)也應(yīng)該清醒地認(rèn)識(shí)到其性能的低下。
Scanner之所以能如此全能,依賴于Java支持的正則表達(dá)式,這點(diǎn)可以自行閱讀文檔或者源碼了解,這里不加詳細(xì)說(shuō)明。
我們?cè)囅?#xff0c;比如一行這樣的數(shù)據(jù):
1 2 555 333333 99 243 ……
如果說(shuō)每一次都用scanner.nextInt(),就會(huì)慢太多。
反反復(fù)復(fù)的IO操作,每次都要判斷和處理,很影響效率的。
比如說(shuō)在洛谷刷算法題的時(shí)候,我一般是用Java,但很多次都被卡死性能,不管怎么優(yōu)化也不行,最后發(fā)現(xiàn)問(wèn)題就在Scanner身上,那怎么處理呢?
答案是換BufferedReader,性能大幅提升。
看下面的代碼:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); int num = Integer.parseInt(reader.readLine()); int[] record = new int[num]; String[] nums = reader.readLine().split("\\s+"); for (int i = 0; i < num; i++) {record[i] = Integer.parseInt(nums[i]); } reader.close();這樣一段代碼就可以先讀一個(gè)數(shù)值,再讀剩下一行里大量的數(shù)值。
看似還要開(kāi)一個(gè)String[],但其實(shí)都說(shuō)過(guò)了,再慢也慢不過(guò)IO,希望大家心里清楚最慢的就是IO了,減少IO是提升性能之道。
不過(guò),在極其苛刻的情況下,Java是沒(méi)辦法完成的,嚴(yán)重TLE+MLE,哪怕你用了byte這樣的也不行,所以就得換C++了。畢竟算法題沒(méi)必要為Java設(shè)計(jì)性能指標(biāo),不達(dá)標(biāo)也只能認(rèn)了,Java比起C/C++太慢了。
Java輸入的一些問(wèn)題
總結(jié)
以上是生活随笔為你收集整理的【Java】深入剖析Java输入输出的那些细节的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 详解Spring框架的AOP机制
- 下一篇: 【VB.NET】VB.NET文件问题的解