08_Java基于文本的应用
本章章节
> 8.1 与用户交互
> 8.2 格式化输出
前面介绍的程序和实例都很少涉及到与用户的交互,都是直接事先就设置好某个值,并没有在程序运行的过程中动态的传入。本章主要讲解一些基于文本的应用和用户交互。
8.1 与用户交互
程序在运行的时候,我们可以给程序传入数据,程序根据输入的数据作出响应。实现与用户的交互。
常见的输入方式有:
命令行参数
标准的输入
系统属性
从文件读入
8.1.1 从命令行传入参数
当一个Java应用程序通过“java Test”从终端启动运行时,用户可以提供零个或多个命令行参数。这些命令行参数都是字符串,这些字符串可以是独立的记号(如:aaa),也可以是引号之间的多个符号("aaa bbb")。
参数序列跟在程序类的名字后面输入;然后被存放在String 对象的数组中,传递给main 方法。如图8-1所示:
图8-1 命令行参数传递
实例:TestArgs.java
public class TestArgs { public static void main(String[] args) { for (int i = 0; i < args.length; i++) System.out.println(args[i]); } }
编译运行方式如图8-2所示:
图8-2 命令行参数传递方式
由图可知,当在命令行中一个参数都不传的时候,没有任何输出结果。这一点跟C语言是有区别的。C语言命令行传递过程中args[0]存放的是可执行程序本身,args[1]才存放的是第一个传递进来的参数。而Java里面args[0]已经表示传递进来的第一个命令行参数了。
8.1.2 控制台标准输入
控制台标准的输入:多数应用都会发生人机交互。人机交互经常通过控制台文本输入/输出来完成。Java 2 SDK用公有类java.lang.System支持控制台I/O。
System.out是一个PrintStream对象,它指向运行Java应用程序的终端窗口。
System.in是一个InputStream对象,它指向用户的键盘。
在jdk 1.5之前,程序通常通过BufferedReader类来读取键盘输入。BufferedReader是java IO流中的一个字符包装流,它必须建立在另一个字符流的基础上,但标准输入System.in是字节流,程序需要使用转换流InputStreamReader将其包装字符流。
实例:TestKeyInput.java
import java.io.*; public class TestKeyInput { public static void main(String[] args) { // 进行字符串的包装,就可以读取一行字符串 InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); System.out.println("按 ctrl+c 键或者输入exit 退出程序!"); try { String s = null; while ((s = br.readLine()) != null && !s.equals("exit")) { System.out.println("Read: " + s); } br.close(); } catch (IOException e) { e.printStackTrace(); } } }
编译运行方式如图8-3所示:
图8-3 利用BufferedReader类读取键盘输入
除了可以利用BufferedReader类来读取键盘输入以外,还可以利用扫描器Scanner。java.util.Scanner类可以很方便地获取用户的键盘输入,jdk 1.5新增工具类,Scanner是一个基于正则表达式的文本扫描器,它可以从文件、输入流、字符串中解析出基本类型值和字符串值。Scanner类提供了多个构造器,不同的构造器可以接受文件、输入流、字符串作为数据源,用于从文件、输入流、字符串中解析数据。
Scanner主要提供了两个方法来扫描输入:
hasNextXxx():是否还有下一个输入项。
其中Xxx可以是Int、Long等代表性基本数据类型的字符串。如果判断是否包含下一个字符串,则可以省略Xxx
nextXxx():获取下一个输入项。例如,nextLine方法将输入一行(使用该方法可以在输入行中包含空格);next方法用于读取一个单词(空格作为分隔符);nextInt方法用于读取一个整数;nextDouble用于读取一个浮点数。
默认情况下,Scanner使用空白(包括空格、Tab空白、回车)作为多个输入项之间的分隔符。如果只使用回车作为分隔符,通过useDelimiter("\n")方法实现。
实例:TestScanner.java
import java.util.*; class TestScanner { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String value = sc.nextLine(); System.out.println("value:" + value); } }
编译运行方式如图8-4所示:
图8-4 利用Scanner类读取键盘输入
因为Scanner输入时可见的,所以Scanner类不适用于从控制台读取密码。JDK1.6特别引入了Console类来实现这一目的。java.io.Console可访问与当前 Java虚拟机关联的基于字符的控制台设备,是jdk 1.6新增工具类。如果你的Java程序要与Windows下的cmd或者Linux下的Terminal交互,就可以用这个Java Console类代劳。
如果此虚拟机具有控制台,那么它将由此类唯一的实例(可通过调用 System.console()方法获得)表示。如果没有可用的控制台设备,那么对该方法的调用将返回 null。
读写操作是同步的,以保证关键操作能完整地完成;因此调用方法 readLine()、readPassword()、format()、printf()以及对reader()和writer()返回对象的读取、格式化和写入操作在多线程情况下可能阻塞。
实例:TestConsole.java
import java.io.*; public class TestConsole { public static void main(String[] args) { Console con = System.console(); con.printf("\t\t********学生信息管理系统********\n\n\n"); con.printf("\t\t\t用户名:"); String userName = con.readLine(); con.printf("\n"); con.printf("\t\t\t密 码:"); char passWord[] = new char[12]; passWord = con.readPassword(); con.printf("\n\n"); System.out.println("你录入的用户名为:" + userName); System.out.println("你录入的密码为:" + new String(passWord)); } }
编译运行方式如图8-5所示:
图8-5 利用Console类读取键盘输入
8.1.3 系统属性给程序输入数据
系统属性是另外一种在运行时向程序传递参数的机制。每个属性都是一个属性名和属性值的映射对。属性名和属性值都是字符串。
Properties 类表示这样的映射;
System.getProperties方法返回系统的属性对象;
System.getProperties(String)方法返回String属性的值;
System.getProperties(String, String)方法允许在属性名不存在时返回默认值。
先看下面的实例,显示系统已经有的属性:
import java.util.*; public class TestSystemProperties1 { public static void main(String[] args) { Properties p = System.getProperties();//获取系统属性,类似map<key, value>结构 p.list(System.out); //通过list方法显示系统属性 } }
从结果看,其实系统属性都是<key, value>结构的。我们可以通过propertyNames函数获取所有的属性key,该函数返回的是一个枚举类集合Enumeration。通过nextElement方法可以遍历整个枚举类,取出每一个属性key,然后通过getProperty(key)的形式得到属性值value。
实例:TestSystemProperties2.java
import java.util.*; public class TestSystemProperties2 { public static void main(String[] args) { Properties p = System.getProperties();//获取系统属性,类似map<key, value>结构 Enumeration e = p.propertyNames(); //获取系统属性的key while (e.hasMoreElements()) { //遍历key String name = (String) e.nextElement(); // 获取key String value = p.getProperty(name); // 获取key对应的value System.out.println("name: " + name + " value: " + value); } } }
上面两个例子如果直接运行,则得到的都是系统属性。还可以采用如下运行方式:
java -Daaa=666 TestSystemProperties2
-D后面是属性的名字,=后面是属性的值,注意是大写的D,属性名和值之间不能有空格。如果要传递多个属性,则可以用如下形式:“-Daaa=666 –Dbbb=777”
编译运行方式如图8-6所示:
图8-6 利用Properties类读取键盘输入
8.2 格式化输出
可以使用System.out.print(x)将数值x输出到控制台上。这条命令将以x对应的数据类型允许的最大非0数字位数打印输出x,例如:
double x = 10000.0 / 3.0;
System.out.println(x);
打印:
3333.3333333333335
如果希望显示美元、美分等符号,则有可能会出现错误。在早期的Java版本中,对于格式化数值引起过一些争议,庆幸的是,从JDK1.5之后,沿用了C语言库函数printf,例如调用System.out.printf("%8.2f", x);按照指定的格式输出。
在printf中,可以有多个参数,例如:
System.out.printf("hello %s, next year, you will %d\n", "zhangsan", 25);
每一个以%字符开始的格式说明符都用相应的参数替换格式说明符尾部的转换符说明被格式化的数值类型:f表示浮点型,s表示字符串,d表示时间值整数。具体的请参考表8-1,如下所示:
表8-1 printf的转换符
转换符 类型 举例 |
|
转换符 类型 举例 |
d 十进制整数 159 x 十六进制整数 9f o 八进制整数 237 f 定点浮点数 15.9 e 指数浮点数 1.59e+01 g 通用浮点数 —— a 十六进制浮点 0x1.fccdp3 |
s 字符串 Hello c 字符 H b 布尔 true h 散列码 42628b2 tc 日期时间 —— % 百分号 % n 与平台有关行分隔符 —— |
另外,还可以给出控制格式化输出的各种标志,如表8-2所示:
表8-2 printf的标志
标志 |
目的 |
举例 |
+ |
打印整数或负数的符号 |
+3333.33 |
空格 |
在正数之前添加空格 |
| 3333.33| |
0 |
数字前面补0 |
003333.33 |
- |
左对齐 |
|3333.33 | |
, |
添加分组分隔符 |
3,333.33 |
#(对于x或o格式) |
添加前缀0x或0 |
0xcafe |
使用规则,例如:
System.out.printf("%,.2f\n", (10000.0 / 3.0));
System.out.printf("%+.2f\n", (10000.0 / 3.0));
System.out.printf("%(.2f\n", (-10000.0 / 3.0));
输出结果为:
3,333.33
+3333.33
(3333.33)
可以使用多个标志,例如:“%,(.2f”。
可以使用静态的方法String.format创建一个格式化的字符串,而不打印输出,类似于C语言中的sprintf函数。
感谢阅读。如果感觉此章对您有帮助,却又不想白瞟