I/O
- 输出用System.out的方法,输入是不是用System.in呢?答案是…………NO!我去……
-
普通输入可以用Scanner类,它属于java.util,所以用之前要
import java.util.*;
用法是
Scanner in = new Scanner(System.in);
然后用这个Scanner对象的方法来读
-
读一行用nextLine(),读一个词用next(),读一个整数用nextInt(),读一个浮点数用nextDouble()
-
要读密码不想明文显示,可以用
Console cons = System.console(); char[] pw = cons.readPassword("Password: ");
注意console的这个readPassword出于安全原因返回的不是String,是char[]。另外它可以接受字符串做prompt
- Console只能一次读一行
- %s 可以用来输出任何implement了Formattable这个interface并且override了formatTo()的类,或者implement了toString()也行
- Java还新加了用来输出时间的%t以及各种组合,还有各种各样的方便输出,参见Formatter
- 输出时间的转换符是有locale的,如果有n个都用的是同一个Date,可以用%n$来指定是format string后的第几个参数,n从1数起
- 静态方法String.format可以用来合成format过的String
文件IO
-
输入用
Scanner in = new Scanner(Path.get("test.txt"));
这样,注意Scanner的构造函数的参数不是一个String,是一个Path,如果是一个String,那么读入的不是文件内容,而就是那个String。各种构造函数的区别看这里.
-
输出用
PrintWriter out = new PrintWriter("test.txt");
这回可以直接传String进去了,简直太不对称了= = 而且要注意这东西是在java.io下面的
- 文件目录相对于执行起Java程序时的工作目录来算
-
因为文件IO可能会抛异常(文件不存在啦,文件创建不了啦之类的),在Java里要对这些操作所在的函数声明你知道会出现这些异常,写法类似于
public static void main(String[] args) throws FileNotFoundException {...}
如果跑java程序的时候用重定向符加上了IO用的文件就可以不用担心这些异常。
控制流
- Java没有goto,虽然goto是它的保留字= =
- Java用{}来定block scope
- Java里没有nested scope的shadowing,能看到同一个scope的就不许有同名变量(果然是防猪队友专用语言),除非这些同名变量定义在for的那句里
- while和if跟C/C++家族的基本差不多
- Java的浮点数也是不能直接比较的
-
Java里依然存在那个很无聊的switch,如果怕出现手误写了个不想要的fall through,可以在编译的时候用
javac -Xlint:fallthrough ...
来开lint警告自己。如果某些函数又要用到fall through,可以加上
@Suppress-Warnings("fallthrough")
来绕过警告
- 如果被switch的是一个enum类型,在case后面的值不用加上enum类型的前缀
大数
- Java自带一个BigInteger来处理超大整数
- 静态函数BigInteger.valueOf可以用来将普通的数字转换成BigInteger对象
- BigInteger不能用加减乘除运算符,因为Java没有运算符重载这种东西,唯一的例外是String的+,不知道Java的设计者们到底是什么脑回路……加减乘除要用add、subtract、multiply、divide这种方法,取余用mod,比较用compareTo(注意返回的不是布尔值,0代表等于之类这样)
- 还有一个对应的BigDecimal来处理超大浮点数,除法还要用上一个RoundingMode,valueOf还支持用个scale来修改数值
数组
-
Java里声明数组可以把[]放在类型那边,像这样
int[] a;
这是推荐的写法,虽然也可以像C/C++一样写
int a[];
-
初始化可以用
array = new Type[size];
的形式,和C/C++不一样的是,这里的size可以是变量,也就是数组大小可以到运行时再确定。这样初始化的数组里面的值是
- 数字就是都0
- 布尔值就都是false
- 对象,包括String,全是null
不会有垃圾值,再一次防止被猪队友坑……
-
声明和初始化写在一起可以
Type[] array = new Type[size];
或者
Type[] array = {t1, t2, ..}
- 数组对应的类叫Arrays,注意有个s
-
一次性填充值可以这样
Arrays.fill(array, value);
- 数组的长度可以用array.length获取(和JS一样~)。Java允许长度为0的数组
-
数组除了可以用new重新赋值以外,还可将先显式初始化匿名数组拿来赋值
array = new Type[] {t1, t2, ...};
- 将一个数组赋给另一个数组是shallow copy,它们会共享一个引用,这点和JS是一样的。Java的数组都放在堆上。
-
如果要得到deep copy,可以用Arrays.copyOf
array1 = Arrays.copyOf(array2, size);
这里的size可以超过array2的大小,多出来的部分会按照初始化的规则填充
- 如果经常要改动数组大小,不如用ArrayList替代
-
Java有类似C++新特性的
for(variable : collection)
的语法,只不过连auto都不用了,会自己做类型推导
-
数组的toString方法可以将数组转换成类似于
"[1,2,3]"
这样的字符串
- []运算符会自动检查是否越界,Java也没有指针算术这种黑魔法
-
main函数的String[]类型的命令行参数里,没有运行程序的名字,像这样
java prog -h
那么命令行参数的第0个元素就是"-h",前面的不算
- Java的数组自带sort方法,用的是改进过的快排,还自带binarySearch,也有equals来做比较
多维数组
-
Java也是支持二维数组的,声明方法类似于
Type[][] matrix;
初始化用
matrix = new Type[size1][size2];
或者
matrix = { {...}, {...}, {...}...};
注意用花括号嵌套区分行
-
for-each loop也要套两遍,且套行的那遍要写类型
for (Type[] row : matrix) for (cell : row) { ... }
-
Arrays有一个deepToString可以把二维数组也转换成字符串,用嵌套的[]和逗号标明
-
其实Java的多维数组也和C/C++一样,是用一维数组伪装的,但是一行行底层不必连续存储,所以不必固定行的宽度。在Java里可以直接将行交换(其实就是换引用)
matrx[1] = matrix[2]
要得到长度不同的行也很容易,先声明有多少行
Type[][] matrix = new Type[size1][];
然后每行赋值一个长度不同的数组就行了,比如
matrix[0] = new Type[50]; matrix[1] = new Type[20];
这样也是OK的