本篇文章是《零根底学Java》专栏的第三篇文章,文章采纳通俗易懂的文字、图示及代码实战,从零根底开始带大家走上高薪之路!

Java程序的命令行参数

咱们能够利用Java程序执行时的命令行参数进行数据的输出。所谓命令行参数,是在执行Java类的命令中,跟在Java类前面的若干由空格分隔的字符序列。如后图。

程序代码

/* * HelloWorldArgs.java *//** * HelloWorld 在规范输出设备中输入“Hello World!” */public class HelloWorldArgs {       public static void main(String[] args) {           System.out.println("Hello World!" + args[0] + args[1]); // Display the string.       }//end method main}//end class HelloWorldArgs

释义

第一,在这段程序中,咱们用到了所有三种正文模式。

第二,在用println办法输入数据的时候,咱们用到了args[0]args[1],这里咱们能够看到,这种模式同C语言中的数组的应用是不是很像?事实上,args就是数组变量,它是main的形式参数,args数组中元素的类型为String(Java中的字符串类型名,它是一个类,属于援用类型,不是根本类型)。

第三,println办法的实参为:"Hello World!"+args[0]+args[1] 这是一个表达式(对于表达式咱们见附录1),其中的+不是算术上的加法,咱们看到+左右都为字符串,那么这里+的作用就是连贯它左右的字符串,形成新的字符串,它是一个字符串连贯运算。

既然是表达式,那么就必须进行计算并产生后果,那么参加运算的args[0]、args[1]的值又是从哪里来的呢?

它们的值从命令行上来,如图所示执行该类:

该图例中,有三个命令行参数,所以args数组的大小为3。因为Java的下标从0开始,所以,args的最初一个元素的下标为2。与C语言相比拟,C语言不对数组下标是否越界进行查看,而Java则要求下标不得越界。在本程序中args的最大下标为1,那么,如果咱们在执行这个java程序的时候,命令行参数少于2个,则会出错,如图:

这里只有一个命令行参数,而咱们在程序中须要2个命令行参数,所以会产生如图所示的异样:java.lang.ArrayIndexOutOfBoundsException,咱们看lang前面的标识符,它是java.lang这个包(包是若干相干类的汇合)中的一个类,这个类代表数组下标越界异样。

第三行的提醒:at HelloWorldArgs.main(HelloWorldArgs.java:11),示意谬误产生在HelloWorldArgs这个类的main办法中,在源文件HelloWorldArgs.java文件的第11行。

大家在当前学习Java的过程中,要学会看出错提醒。

应用BufferedReader进行输出

BufferedReader类是一种Java规范类中的一个负责从字符输出流中读取文本的类。为了提高效率,对流中的字符进行缓冲,从而实现字符、数组和行的高效读取的一个类。这个类的全称java.io.BufferedReader,其中java.io是一个包(package)名,顾名思义,这个包是同java的输入输出相干的 类及子包的汇合。

什么是包呢?这个问题,咱们这里要略知一二。简略的讲,你能够把包设想为一个箱子,这个箱子中放着性能相干的货色(类),还能够在大箱子中放小箱子(子包)。所以,大家能够晓得下面的java.iojava是大箱子,io为小箱子,BufferedReader这个类是io这个子包中的一个性能类。这些包以何种模式保留的呢?答案是,以文件夹的模式保留,如图:

在JDK的装置目录中,有个压缩文件:src.zip,所有的JDK的源代码均在这里,有抱负钻研java的同学,能够读读这些代码,看看巨匠和菜鸟之间的区别。咱们用解压软件关上能够看到整个JDK的包构造,就本图,咱们能够看到BufferedReader这个类的源码就在那里,而且io下再无子包。

大家可能说,源代码是无奈执行的,那能够执行的.class文件在哪里呢?在JDK的 jre\lib文件夹下有个rt.jar文件,大家用解压软件关上它,就能够看到JDK中所有的.class文件均在这里。如图:

这里大家要留神包名的命名规定,包名中所有的字母均为小写字母,这是大家约定俗成的规定。

BufferedReader

原理

这个类的性能很弱小,它的性能不仅仅局限在从键盘中输出数据。目前,咱们先只学习利用该类如何从键盘输入数据。

首先,如果咱们心愿BufferedReader这个类为咱们服务,就必须创立这个类的对象(不是所有的类都必须创建对象能力用,比方咱们罕用的System类,就是间接用了,怎么辨别,咱们当前缓缓理解,这里咱们记着咱们学过的每个类的应用形式),如下代码:

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

这行代码中,咱们通过 new BufferedReader(实参)创立了一个对象(什么?实参?难道BufferedReader(实参)是办法调用?不错,这里就是办法调用,只不过这里的这个办法是BufferedReader的构造方法。所谓构造方法,咱们先简略了解为创建对象时会执行的办法,该办法不同于一般办法,它没有返回值类型,甚至连void都没有,构造方法只能由new应用,不能把构造方法当作一般办法调用),这个对象的援用放在了 br 这个变量中,留神不是这个对象放在br中,而是这个对象的援用放在了br中。

那么大家肯定疑难了,什么是援用?如果比照C语言,这里援用相当于C中的指针,只不过Java中的援用值自身是不能像C中的指针一样进行数值的操作的,比方不能像C一样对指针进行值的加减等。如果以内存存储的角度来看,br变量是保留在栈中的,而对象是保留在堆中的,所以,br中只是保留了对象的地址,这里咱们把它叫做援用。援用就代表那个对象。咱们能够很天然的通过援用对对象进行操作。这就像电视机与遥控器的关系,电视机就是对象,遥控器就是援用,遥控器丢了就不能操纵电视机了,尽管电视机还在那里,所以援用应该保存起来,本例中新建对象的援用就是保留在br中。

大家可能还有疑难,“类”和“对象”又是什么关系?咱们再做个类比,“类”就是盖楼的图纸,“对象”就是盖成的大楼。有了图纸,不代表这个“类”就能够用了,只有楼盖好了,咱们能力应用楼(实体存在的楼)的性能。所以,咱们在写Java程序的时候都是先设计类,再创立该类的对象(还是那句话,有些类不须要创建对象就可应用)。

那么,这行语句中的 new InputStreamReader(System.in)又是什么用呢?咱们看到new就晓得是创建对象,这里创立的是 InputStreamReader这个类的对象,创立实现的对象的援用,作为实参传递给创立BufferedReader类对象的构造方法,而后这个InputStreamReader对象就由br援用的BufferedReader对象应用了(那到底怎么用的呢?由BufferedReader封装起来了,那是个黑盒子,大家没必要晓得)。

为什么必须有个InputStreamReader对象呢?这是因为在Java零碎中,数据传递的形式是以“流”的模式进行的,流是在Java零碎中对待数据传递的一种模式,就像水管中的水,只不过这根水管很细,在水管中流动的数据排队流过。在Java中有两种数据流,一种是“字节流”,一种是“字符流”,也就是说这根水管中流过的数据是字节还是字符。BufferedReader解决的数据必须是字符流,而代表规范输出设施-键盘的Systems.in,它解决的数据是字节流输出数据,怎么对接呢?这就须要InputStreamReader进行字节流向字符流的转换,到这里大家是不是明确了呢?如图:那至于InputStreamReader是怎么转换的,咱们就不须要晓得了,咱们只有晓得它能转换就行了。

InputStreamReader类的全称为java.io.InputStreamReader,后面的是包名不消说了。

接下来咱们就能够应用BufferedReader的对象来对数据进行解决了。怎么做呢?就是通过对象来调用对象中的办法来实现相应的性能,这里咱们先看看BufferedReader这个类中罕用的办法。

返回值类型办法名及参数办法的性能可能产生的异样
BufferedReader(Reader in)它是构造方法,创立一个应用默认大小输出缓冲区的缓冲字符输出流对象。参数为字符流对象
BufferedReader(Reader in,int sz)它是构造方法,创立一个由sz指定大小输出缓冲区的缓冲字符输出流对象。
voidclose()敞开该流并开释与之关联的所有资源。IOException
intread()读取单个字符,读取到的字符编码以int值返回,因为字符的编码为两个字节,所以,返回值的范畴为0~65535(0x0000 ~ 0xffff),如果返回值为-1,则示意已达到流的开端,流中再没有数据。IOException
intread(char[] cbuf, int off, int len)将字符顺次读入到 cbuf 数组的 off 下标(数组的下标从0开始)开始处,冀望都len个字符,但理论因为流中可能没有那么多字符,理论读取的字符个数以办法的返回值返回。返回值如果是-1,示意已达到流的开端。IOException
StringreadLine()在流中读取一个文本行,行是以换行 ('\n')、回车 ('\r') 或回车后间接跟着换行终止的。这个文本行以字符串的模式返回,留神字符串中不含有行结束符。返回值为null示意达到流的开端IOException
booleanready()判断此流是否已筹备好被读取。IOException
voidmark(int readAheadLimit)标记流中的以后读取地位。readAheadLimit示意在做过该标记当前,可读取字符的数量,如果标记当前再读取字符的数量超出了改数值当前,执行reset办法可能会失败。readAheadLimit的值不应大于输出缓冲区的大小,如果大于输出缓冲区的大小了,零碎会从新再调配一个新的缓冲区。所以应该小心应用readAheadLimit这个实参值,不要太大。如果产生I/O谬误,会抛出IOException;如果readAheadLimit<0,会抛出IllegalArgumentException,该异样不需解决。
booleanmarkSupported()判断此流是否反对 mark() 操作(它肯定反对)。
voidreset()将流的输出地位重置到最初一次做的标记处。IOException
longskip(long n)从以后读取地位跳过n个字符,n为期望值,理论跳过的字符数以返回值的模式返回。n的值应该为非正数。如果产生I/O谬误,会抛出IOException;如果n为正数,则抛出IllegalArgumentException,该异样不需解决。

程序示例

性能需要1:

从键盘上输出一串字符,以回车作为完结,而后把输出的字符再回显到屏幕上

  • 需要剖析:从需要,咱们晓得,咱们只须要输出一行内容,而且输出数据为字符,咱们利用后面提到的BufferedReader来进行实现。
  • 程序编码:

    public class TestBufferedReader1{    public static void main(String[] args) {        //创立一个BufferedReader对象,筹备进行字符串的输出        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        //读入输出行,后果保留在str中        String str = br.readLine();        //将str中的内容输入到屏幕        System.out.println(str);    }}

    大家把下面的代码用Sublime保留为TestBufferedReader.java,在解决好字符编码问题当前,进行编译,会怎么样?出错了?!出错信息是: 怎么办?

    咱们要认真看出错信息显示的是什么,找不到符号...,找不到哪些呢?图中的那些数字示意出错的行号,^指定的为出错的具体位置,别离是BufferedReader、InputStreamReader

    OMG!怎么办?

    大家还记得咱们用的这两个类的全称是什么?回顾一下。好了,咱们在用这两个类的时候,如果不加上包名,java编译器就不意识,那咱们加上试试,代码如下:

    public class TestBufferedReader2{    public static void main(String[] args) {        //创立一个BufferedReader对象,筹备进行字符串的输出        java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));        //读入输出行,后果保留在str中        String str = br.readLine();        //将str中的内容输入到屏幕        System.out.println(str);    }}

    编译后果如图:原来的找不到符号的谬误没有了,然而怎么又多出一个“未报告的异样谬误”问题呢?什么时候能力没有问题啊?!

    大家稍安勿躁,遇到问题,咱们不怕,对于初学者来讲,遇到越多的问题,咱们应该越快乐,因为,每修改一个谬误,咱们就学到了一点货色。好吧,咱们来看看谬误提醒,在代码的第六行有个“ 未报告的异样谬误IOException; 必须对其进行捕捉或申明以便抛出”谬误,问题给你指出来了,而且还有解决方案,挺好。然而怎么“捕捉”或者“申明”呢?

    1. 咱们先看看怎么申明:咱们在main办法的前面加上throws IOException(这里throws是加字母s的哦),试试看,代码如下:

      public class TestBufferedReader3{ public static void main(String[] args) throws IOException{     //创立一个BufferedReader对象,筹备进行字符串的输出     java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));     //读入输出行,后果保留在str中     String str = br.readLine();     //将str中的内容输入到屏幕     System.out.println(str); }}

      编译后,如图:

      怎么又成找不到符号了,这次是找不到IOException,联合后面的教训,咱们晓得,这里还是须要用全名:java.io.IOException,好了,咱们再改改:

      public class TestBufferedReader4{ public static void main(String[] args) throws java.io.IOException{     //创立一个BufferedReader对象,筹备进行字符串的输出     java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));     //读入输出行,后果保留在str中     String str = br.readLine();     //将str中的内容输入到屏幕     System.out.println(str); }}

      编译后,如图:

      咱们常常说:“没有音讯就是好消息”,这里没有任何提示信息,就表明,咱们的源代码编译通过了。咱们能够测试看看:

      能够运行了。

    2. 咱们再来看看怎么捕捉异样:这个麻烦一点,咱们须要应用异样捕捉语句,它的个别写法如下:

      try{ /*可能会产生异样的语句,一旦产生异样,就不论产生异样语句的前面还有多少语句没有执行而中断try中的语句的执行,零碎会生成可能形容相干异样的异样类对象,这个异样类对象由前面的匹配的catch捕捉,从而进入相干catch进行异样解决 */} catch(异样类名1 e) { //一旦产生异样,由catch捕捉,在这里写出对异样的解决代码} catch(异样类名2 e){ //仍然是解决当和异样类名2相匹配的异样产生时,须要做的工作} //如果try块中可能产生n种异样,这里就须要写n个catch语句来进行捕捉finally{ /*finally这部分子句是能够没有的,视状况而定。finally子句中的代码不论try中是否产生异样,最终都会执行finally子句中的语句。*/} 

      咱们从编译提示信息,咱们晓得 br.readLine(); 可能会呈现IOException异样,而这个异样,咱们没有捕捉。那咱们就用下面的异样解决语句来做一下,代码改成:

      public class TestBufferedReader5{ public static void main(String[] args){     //创立一个BufferedReader对象,筹备进行字符串的输出     java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));     try{         //读入输出行,后果保留在str中         String str = br.readLine();         //将str中的内容输入到屏幕         System.out.println(str);     } catch(java.io.IOException e){//这里咱们记得用IOException的全名         //打印异样栈信息         e.printStackTrace();     }  }}

      编译执行,没有问题。

    3. 那这两种形式有什么区别呢?咱们从异样解决语句,咱们能够看到,一旦产生异样,咱们能够被动由catch来进行捕捉解决。所以,这两种解决形式,第一种是不被动的形式,就是说,写这段代码的程序员筹备把产生的异样提交给调用这个办法的代码来进行解决,在办法外部不解决;第二种形式是比拟被动的,一旦产生异样,这个异样在本办法外部就进行了解决,不再提交给调用它的代码来解决了。这就好比一个工厂中的一个车间,在车间的生成过程中,如果产生一些生产事变,有些事变车间主任就能够解决,有些事变必须上报到厂长那里,有些可能厂长也无奈解决,就须要进一步上报。那么,本人解决就用catch,上报的话,就在办法的前面加上 throws 若干异样类名throws前面能够有若干异样类名,两头用,隔开),本人解决的异样就不要上报了。

    等等,当初是不是功败垂成了呢?还有收尾工作没有做完:对于流的操作,咱们在不应用流的时候,肯定记得把流敞开了,这就像用水,不用水的时候,要记得把水龙头拧住。怎么做呢?在操作流的最初一步,执行close办法,咱们一次性把代码补齐,代码如下(咱们用异样捕捉来做):

    public class TestBufferedReader6{    public static void main(String[] args){        //创立一个BufferedReader对象,筹备进行字符串的输出        java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));        try{            //读入输出行,后果保留在str中            String str = br.readLine();            //将str中的内容输入到屏幕            System.out.println(str);        } catch(java.io.IOException e){            //打印异样栈信息            e.printStackTrace();        } finally {            try{                br.close();            }catch(java.io.IOException e){                //打印异样栈信息                e.printStackTrace();            }        }    }}

    大家是不是有点疑难,为什么把close放在finally子句中,而且close自身又套了一层try...catch语句?首先,为了保障不论readLine有没有产生异样,咱们的流都要敞开,所以,close必须放在finally子句中,以保障close必须执行;其次,close办法也可能产生IOException异样,所以close里面也要再套一层try...catch语句。

    到这里程序的编译到运行曾经没有问题了,然而,咱们有没有感觉总是在类名前加包名是不是太累赘?有没有方法呢?方法总是比问题多。咱们能够在源文件的最开始加上若干 import 包名.类名;或者 import 包名.*;,比方下面的代码,咱们能够这么做:

    import java.io.BufferedReader;  import java.io.InputStreamReader;  import java.io.IOException;//上面所应用类名就不用应用全名了,是不是清新了许多?public class TestBufferedReader6{    public static void main(String[] args){        //创立一个BufferedReader对象,筹备进行字符串的输出        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        try{            //读入输出行,后果保留在str中            String str = br.readLine();            //将str中的内容输入到屏幕            System.out.println(str);        } catch(IOException e){            //打印异样栈信息            e.printStackTrace();        } finally {            try{                br.close();            }catch(IOException e){                //打印异样栈信息                e.printStackTrace();            }        }    }}

    咱们还能够这么做:

    import java.io.*;//上面所应用类名就不用应用全名了,是不是清新了许多?public class TestBufferedReader6{    public static void main(String[] args){        //创立一个BufferedReader对象,筹备进行字符串的输出        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        try{            //读入输出行,后果保留在str中            String str = br.readLine();            //将str中的内容输入到屏幕            System.out.println(str);        } catch(IOException e){            //打印异样栈信息            e.printStackTrace();        } finally {            try{                br.close();            }catch(IOException e){                //打印异样栈信息                e.printStackTrace();            }        }    }}

    这两种模式上的区别在于,后者应用了通配符*,这*代表相应子包中的所有类,留神只是这个子包中的所有类,是不蕴含子包中的子包的。比方下面的 import java.io.*; 是不能写作 import java.*; 的。因为后者的 * 只是代码java这个包中的所有类,而不蕴含它的子包 java.io

    大家是不是感觉用 挺不错的,省事。然而咱们倡议大家应用第一种计划,这是因为应用 会一股脑地把相应子包中的所有类都引入了,而不论你的程序用不必那些类;而不必 * 的形式,咱们只是用什么才引入什么,咱们能够很好的限度咱们代码出错的几率。

    仔细的同学会发现一个问题,那就是System也是类,怎么就没有用全名呢?System的全名为:java.lang.System ,从全名咱们晓得System类在java.lang这个包中,JDK对这个包总是默认引入的,也就是说对于所有的java源代码,相当于在源代码的最开始都有个import java.lang.*;,这条语句是省略的。

性能需要2:

后面的代码只能输出一行文字,如果输出多行呢?每输出一行就回显一行。

  • 需要剖析:从需要,咱们晓得,咱们须要输出多行内容,每输出一行都是以回车完结来这行的。咱们想到能够用循环来实现。循环是须要完结的,咱们怎么来完结输出呢?总不能让这个程序永远运行上来吧。对于键盘的输出,如果要完结这个输出流,咱们在最初输出ctrl+z,再输出回车就能够了。而readLine这个办法在遇到流的开端的时候,它的返回值为null
  • 程序编码:

    import java.io.BufferedReader;  import java.io.InputStreamReader;  import java.io.IOException;public class TestBufferedReader7{    public static void main(String[] args){        //创立一个BufferedReader对象,筹备进行字符串的输出        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        try{            //读入输出行,后果保留在str中            String str;             /*咱们留神while的循环条件的写法,str = br.readLine()是一个赋值表达式,凡表达式都是有计算加后果的,它的计算结果就是赋值到str中的值            */            while((str = br.readLine()) != null){                //将str中的内容输入到屏幕                System.out.println(str);            };                        } catch(IOException e){            //打印异样栈信息            e.printStackTrace();        } finally {            try{                br.close();            }catch(IOException e){                //打印异样栈信息                e.printStackTrace();            }        }    }}

这里只有咱们编译胜利当前再运行,都没有产生异样的状况,咱们怎么能力看到异样呢?咱们如果心愿java的规范输出零碎产生异样,这种概率切实太小了。有一种方法,咱们本人生成异样,来验证一下异样的解决,代码如下:

import java.io.BufferedReader;  import java.io.InputStreamReader;  import java.io.IOException;public class TestIOException{    public static void main(String[] args){                try{            throw new IOException(); //生成一个IOException异样对象并抛出,这个throw不带s哟            System.out.println("能显示这一行吗?");                } catch(IOException e){            //打印异样栈信息            e.printStackTrace();        } finally {            System.out.println("不论怎么样,都会显示这一行");        }    }}

编译的时候,会呈现如图所示的谬误:

也就是说在编译的时候,java零碎就曾经探知到throw前面的语句是无论如何都不会执行到的。

那咱们把它去掉再试试。如图:

框中的信息是 e.printStackTrace(); 的执行后果。

从这个示例,咱们晓得,异样的产生也可能是程序在运行过程中呈现问题,由零碎被动产生用于代表相干异样的异样对象,也能够由代码被动产生异样。

如果咱们将下面的代码再批改一下,把catch的参数由IOException改为Exception,会怎么样呢?大家就会发现,没有任何问题,仍然能够捕捉。这是什么情理呢?catch后的参数不是同产生的异样准确匹配吗?咱们晓得Java语言是面向对象的语言,面向对象的概念中,类之间是能够有继承关系的,在同一个继承链中,处于继承关系底层的类能够看作是一个处于高层的类类型,就本例来讲,咱们能够说IOException is Exception。其实,这很好了解,就如同:不论松树、柳树、杨树,它们都是树 是一个情理的。不在一个继承链中的类不能这么讲,比方,咱们不能说:石头是树 一样。在JDK中,所有的类都有一个根类:Object,所有的类都继承自该类。

性能需要3:

实现如图所示的性能:

  • 需要剖析:从需要,咱们晓得,咱们须要提示信息和输出混合在一起,提示信息的输入,咱们能够应用System.out.print()来显示。这里要害有一点,咱们要计算第一个整数和第二个整数的和,而br.readLine()读取的数据为字符串而非整数,这里就须要把读到的字符串数据转换为整数。要做到这一点,咱们须要应用int的封装类Integer,该类中有一个办法:

    public static int parseInt(String s) throws NumberFormatException

    通过这个办法的首部,咱们能够失去什么信息呢?该办法的返回值类型为int,参数类型为String,它的修饰符中有一个static,它可能抛出 NumberFormatException 异样。static修饰符的作用,就是通知咱们这个办法,能够应用类名间接应用,不须要创立类的对象,再通过对象应用它。

  • 程序编码:

    import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.IOException;public class TestBufferedReader8 {    public static void main(String[] args) {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int first; //用于存储输出的第一个整数        int second; //用于存储输出的第二个整数        int result; //用于存储计算结果        String str;        try{            System.out.print("请输出第一个整数:"); //咱们没有用println办法            str = br.readLine(); //可能会产生IOException异样            first = Integer.parseInt(str); //将字符串转换为整数,如果str中的字符串格局不能转换为整数,会产生NumberFormatException            System.out.print("请输出第二个整数:");            str = br.readLine();            second = Integer.parseInt(str);            result = first + second;            System.out.println("后果为:" + result);        } catch(IOException e) {//产生IOException异样时,执行上面的代码            e.printStackTrace();            System.out.println("产生了IO异样");        } catch(NumberFormatException e) {//产生NumberFormatException异样时,执行上面的代码            e.printStackTrace();            System.out.println("产生了数字格局异样");        } finally {            try{                br.close();            }catch(IOException e){                //打印异样栈信息                e.printStackTrace();            }        }        }    }

    咱们对下面的编码进行编译,别离执行两次,第一次,输出的数字为合格的整数模式;第二次,输出的数字格局不合格,察看景象,如图:

    从图中,咱们看到第二次会产生格局转换谬误,并输入提示信息。

    如果咱们把下面的代码再扭转一下,如下:

    import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.IOException;public class TestBufferedReader8 {    public static void main(String[] args) {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int first; //用于存储输出的第一个整数        int second; //用于存储输出的第二个整数        int result; //用于存储计算结果        String str;        try{            System.out.print("请输出第一个整数:"); //咱们没有用println办法            str = br.readLine(); //可能会产生IOException异样            first = Integer.parseInt(str); //将字符串转换为整数,如果str中的字符串格局不能转换为整数,会产生NumberFormatException            System.out.print("请输出第二个整数:");            str = br.readLine();            second = Integer.parseInt(str);            result = first + second;            System.out.println("后果为:" + result);        } catch(Exception e) {//产生Exception异样时,执行上面的代码            e.printStackTrace();            System.out.println("产生了其余异样");        } catch(IOException e) {//产生IOException异样时,执行上面的代码            e.printStackTrace();            System.out.println("产生了IO异样");        } catch(NumberFormatException e) {//产生NumberFormatException异样时,执行上面的代码            e.printStackTrace();            System.out.println("产生了数字格局异样");        } finally {            try{                br.close();            } catch(IOException e){                //打印异样栈信息                e.printStackTrace();            }        }        }    }

    咱们编译一下,看看:

    怎么会呈现这些信息呢?这是因为Exception这个类是所有异样类的根类,因而,如把catch(Exception e)放在所有的catch后面,就会导致所有其它的catch不会被执行,java编译器在编译这段代码的时候能发现这类问题,于是就报错了。如果咱们把catch(Exception e)放在最初,就不会呈现问题了,它的意义在于,如果产生的异样不能被catch(Exception e)前的若干catch子句捕捉的话,必会被最初的catch(Exception e)捕捉,换句话说,就是不论产生什么样的异样,咱们的代码都能捕捉了,是不是更好些呢?代码如下:

    import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.IOException;public class TestBufferedReader8 {    public static void main(String[] args) {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int first; //用于存储输出的第一个整数        int second; //用于存储输出的第二个整数        int result; //用于存储计算结果        String str;        try{            System.out.print("请输出第一个整数:"); //咱们没有用println办法            str = br.readLine(); //可能会产生IOException异样            first = Integer.parseInt(str); //将字符串转换为整数,如果str中的字符串格局不能转换为整数,会产生NumberFormatException            System.out.print("请输出第二个整数:");            str = br.readLine();            second = Integer.parseInt(str);            result = first + second;            System.out.println("后果为:" + result);        } catch(IOException e) {//产生IOException异样时,执行上面的代码            e.printStackTrace();            System.out.println("产生了IO异样");        } catch(NumberFormatException e) {//产生NumberFormatException异样时,执行上面的代码            e.printStackTrace();            System.out.println("产生了数字格局异样");        } catch(Exception e) {//产生Exception异样时,执行上面的代码            e.printStackTrace();            System.out.println("产生了其余异样");        } finally {            try{                br.close();            } catch(IOException e){                //打印异样栈信息                e.printStackTrace();            }        }        }    }

    本例演示的是字符串向整数的转换,如果须要输出其余类型数据,大家能够参考JDK说明书对相应根本类型的封装类的阐明。

应用Scanner进行输出

Scanner类是一个能够应用正则表达式来解析根本类型和字符串的简略文本扫描器。它的输出流不局限于键盘输入。该类的性能很弱小,咱们这里只波及咱们要用到的货色,残缺的阐明大家参考JDK说明书。

介绍

Scanner 应用分隔符将其输出合成为各个不同的局部(称为token),默认状况下应用空白作为分隔符。咱们能够应用该类中的useDelimiter办法来设置不同的分隔符。

Scanner类中有很多不同的next为前缀的办法,咱们能够应用不同的 next 办法将合成失去的token转换为不同类型的值。比方,咱们能够应用nextInt()将下一个要被解决的token转换为int数据。

如何判断咱们要解决的token是不是还有呢?Scanner类中也提供了一系列以hasNext为前缀的办法来判断是否还有要解决的token,如果还有,hasNext办法的返回后果为true,否则就是false

Scanner在应用的时候,也是须要创立该类的对象,而后利用该对象来实现工作的。

应用该类的个别流程如下:

  • 创立Scanner对象,同时设置输出源
  • 设置分隔符(如果应用默认的空白符的话,这步是能够省略的)
  • 对输出的数据进行操作
  • 敞开扫描器

示例1

咱们设置一个字符串,它的内容为: mew, I want to fish 13 fishes.。咱们把这个字符串用Scanner进行扫描来看看后果如何。代码如下:

//Scanner在java.util包中,须要引入import java.util.Scanner;public class TestScanner1{    public static void main(String[] args) {        String inStr = "mew, I want to fish 13 fishes."; //建设输出源数据        Scanner sc = new Scanner(inStr);//创立扫描器        //sc.useDelimiter();        //对数据源进行扫描解决        while (sc.hasNext()) {            //next()办法的返回值类型为String            //所以本例是把所有的token都看作字符串来进行输入            System.out.println(sc.next());        }        sc.close();//敞开扫描器    }}

运行后果如图:

从运行后果,咱们能够看到原始的字符串,通过扫描器,按默认的空白符为分隔符,把它分成了7个token,每个tokennext()办法以字符串进行解决。

示例2

咱们还按下面的数据源,这次,咱们扭转一下分隔符,改为,,看看成果。代码如下:

//Scanner在java.util包中,须要引入import java.util.Scanner;public class TestScanner2{    public static void main(String[] args) {        String inStr = "mew, I want to fish 13 fishes."; //建设输出源数据        Scanner sc = new Scanner(inStr);//创立扫描器        sc.useDelimiter(",");//设置分隔符为: “,”        //对数据源进行扫描解决        while (sc.hasNext()) {            //next()办法的返回值类型为String            //所以本例是把所有的token都看作字符串来进行输入            System.out.println(sc.next());        }        sc.close();//敞开扫描器    }}

运行后果如图:

以“,”为分隔符,将原始数据源分隔成了两个token。那么能不能设置多种分隔符呢?答案当然是能够的,咱们只须要在设置useDelimiter办法参数字符串的时候,把分隔符用|分隔开就行了,比方上例:咱们把空格和逗号都作为分隔符,咱们把下面的设置分隔符语句改为 sc.useDelimiter(" |,");即可(留神:| 后面有个空格)。大家本人测试一下吧。

示例3

还按下面的数据源,这次,咱们把数据源中所有的整数提取进去,咱们把代码批改如下:

//Scanner在java.util包中,须要引入import java.util.Scanner;public class TestScanner3{    public static void main(String[] args) {        String inStr = "mew, I want to fish 13 fishes."; //建设输出源数据        Scanner sc = new Scanner(inStr);//创立扫描器        //咱们用循环对token序列顺次进行扫描        //仍然由hasNext()作为是否有下一个token的判断条件        while (sc.hasNext()) {            //判断下个token是否为可转换为int的数据            if(sc.hasNextInt()){//如果能够转换为int数据,把它输入进去                System.out.println(sc.nextInt());            }else {//如果不是,就用next办法把该token略过,持续到下个循环判断下个token的状况                        sc.next();            }        }        sc.close();//敞开扫描器    }}

问题

  1. 如果应用Scanner对键盘进行输出,咱们只须要在创立扫描器的时候,把System.in作为参数传递给Scanner的构造方法就能够了,其余的操作是雷同的,既是Scanner sc = new Scanner(System.in); 。本题的要求就是设计一个应用Scanner实现键盘的数据输出的程序,输出内容要回显到屏幕上。
  2. 扫描 "123 3.45 true a56 ok!"这个字符串,并输入如图的后果: