乐趣区

关于java:零基础学Java第三节基本输入输出

本篇文章是《零根底学 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 指定大小输出缓冲区的缓冲字符输出流对象。
void close() 敞开该流并开释与之关联的所有资源。 IOException
int read() 读取单个字符,读取到的字符编码以 int 值返回,因为字符的编码为两个字节,所以,返回值的范畴为 0~65535(0x0000 ~ 0xffff),如果返回值为 -1,则示意已达到流的开端,流中再没有数据。 IOException
int read(char[] cbuf, int off, int len) 将字符顺次读入到 cbuf 数组的 off 下标(数组的下标从 0 开始)开始处,冀望都 len 个字符,但理论因为流中可能没有那么多字符,理论读取的字符个数以办法的返回值返回。返回值如果是 -1,示意已达到流的开端。 IOException
String readLine() 在流中读取一个文本行,行是以换行 (‘\n’)、回车 (‘\r’) 或回车后间接跟着换行终止的。这个文本行以字符串的模式返回,留神字符串中不含有行结束符。返回值为 null 示意达到流的开端 IOException
boolean ready() 判断此流是否已筹备好被读取。 IOException
void mark(int readAheadLimit) 标记流中的以后读取地位。readAheadLimit 示意在做过该标记当前,可读取字符的数量,如果标记当前再读取字符的数量超出了改数值当前,执行 reset 办法可能会失败。readAheadLimit 的值不应大于输出缓冲区的大小,如果大于输出缓冲区的大小了,零碎会从新再调配一个新的缓冲区。所以应该小心应用 readAheadLimit 这个实参值,不要太大。 如果产生 I / O 谬误,会抛出 IOException;如果 readAheadLimit<0,会抛出 IllegalArgumentException,该异样不需解决。
boolean markSupported() 判断此流是否反对 mark() 操作(它肯定反对)。
void reset() 将流的输出地位重置到最初一次做的标记处。 IOException
long skip(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!” 这个字符串,并输入如图的后果:
退出移动版