1. Math类及其常用方法
Math是一个静态类用于数学计算(比如四舍五入、幂、绝对值、随机数等)。
// 3.0
System.out.println(Math.floor(3.14));
// 3.0
System.out.println(Math.floor(3.54));// 3
System.out.println(Math.round(3.14));
// 4
System.out.println(Math.round(3.54));// 随机生成 0 - 100 之间的数字。
int random = (int)Math.random() * 100 + 1;
2. System类及其常用方法
System.exit(0)
: 退出程序。System.currentTimeMillis()
:获取当前系统时间,单位为毫秒,毫秒转为秒除以1000。
public static void main(String[] args) {
System.out.println("1");// 退出代码执行System.exit(0);// 下面代码得不到执行System.out.println("2");
}
public class Test {
public static void main(String[] args) {
long beginTime = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {
System.out.println(i);}long endTime = System.currentTimeMillis();long totalTime = endTime - beginTime;System.out.println(totalTime);}
}
3. Object类的toString()和equals()方法
3.1 toString()
当使用System.out.println(obj)
来输出一个对象时默认是输出一个字符串,这个字符串并对开发人员来说并没有什么太有用的信息,当打印一个对象时其实就是调用该对象的toString()方法,相当于在执行System.out.println(obj.toString())
。
public class Student {
private String name;private int age;// Getter & Setter
}
public class Test {
public static void main(String[] args) {
Student student = new Student();student.setName("mengday");student.setAge(30);// com.itheima.demo.Student@2503dbd3System.out.println(student);System.out.println(student.toString());}
}
我们把鼠标放在println()方法上按住Ctrl键点击println()方法来查看println()方法的具体实现。
打印对象其实是打印对象的toString()方法,默认使用Object类的toString()方法,而Object类的toString()方法并不能反映对象的信息,所以建议所有类都要重写Object类的toString()方法,一般toString()方法会把对象的所有属性给打印出来,toString()可以通过IDE来自动生成。
public class Student {
private String name;private int age;@Overridepublic String toString() {
return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
3.2 equals()
- == 用于比较对象的内存地址是否相同
- equals() 方法用于比较对象的内容是否相同,equals() 方法默认使用==来比较的,也就是比较内存地址的,如果我们要比较对象的内容是否相同需要重写该方法,选择我们要比较的依据,即两个对象依据什么判定相等。equals()方法也是可以通过IDE来自动生成的。
public class Test {
public static void main(String[] args) {
Student student = new Student();student.setName("mengday");student.setAge(30);Student student2 = new Student();student2.setName("mengday");student2.setAge(30);// falseSystem.out.println(student == student2);}
}
public class Student {
private String name;private int age;// Getter & Setter@Overridepublic String toString() {
return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {
if (this == o) return true;if (!(o instanceof Student)) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}
}
public class Test {
public static void main(String[] args) {
Student student = new Student();student.setName("mengday");student.setAge(30);Student student2 = new Student();student2.setName("mengday");student2.setAge(30);// falseSystem.out.println(student.equals(student2));}
}
4. Objects类以及常用方法
Objects一个工具类,提供一些常用的工具方法用来操作Object对象。Objects的所有方法都是静态的,可以直接通过类名来调用,Objects的构造方法是私有的,不允许new,即使通过反射来创建对象也会抛出异常。
Objects.equals() 与 object.equals(obj)的区别是Objects可以避免空指针异常, 所以以后就别在使用Object中的equals()方法了,这种方法已经被淘汰了,以后都要使用Objects.equals()。
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
public static void main(String[] args) {
String foo = null;String foobar = "foo";// NullPointerException// System.out.println(foo.equals(foobar));// falseSystem.out.println(Objects.equals(foo, foobar));
}
deepEquals 用于比较数组的内容是否相同。
public static boolean deepEquals(Object a, Object b) {
if (a == b)return true;else if (a == null || b == null)return false;elsereturn Arrays.deepEquals0(a, b);
}
public static void main(String[] args) {
int[] array = {
1, 2, 3};int[] array2 = {
1, 2, 3};// trueSystem.out.println(Objects.hashCode(args));
}
Object.hashCode()类似,只是在对象为null时返回的散列值为0而已。
public static int hashCode(Object o) {
return o != null ? o.hashCode() : 0;
}
用于生成对象的散列值,包括数组。
public static int hash(Object... values) {
return Arrays.hashCode(values);
}
Objects.toString()最终也是调用对象的toString(),只不过对于null做了判断。
public static String toString(Object o) {
return String.valueOf(o);
}
public static String toString(Object o, String nullDefault) {
return (o != null) ? o.toString() : nullDefault;
}
用于比较两个对象。
public static <T> int compare(T a, T b, Comparator<? super T> c) {
return (a == b) ? 0 : c.compare(a, b);
}
用于断言判断对象是否为空,如果为空抛出异常并指定异常信息。
public static <T> T requireNonNull(T obj) {
if (obj == null)throw new NullPointerException();return obj;
}
public static <T> T requireNonNull(T obj, String message) {
if (obj == null)throw new NullPointerException(message);return obj;
}
public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
if (obj == null)throw new NullPointerException(messageSupplier.get());return obj;
}
用于判断对象是否为null。
public static boolean isNull(Object obj) {
return obj == null;
}
public static boolean nonNull(Object obj) {
return obj != null;
}
public static void main(String[] args) {
String foobar = null;// trueSystem.out.println(Objects.isNull(foobar));// NullPointerException: foobar值不能为nullObjects.requireNonNull(foobar, "foobar值不能为null");
}
5. BigDecimal类及其常用方法
一:简介
Java中的简单浮点数类型float和double不能够进行运算,或者运算会丢失精度,不光是Java,在其它很多编程语言中也有这样的问题。在大多数情况下,计算的结果是准确的,float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用 java.math.BigDecimal
// 浮点型计算不准确示例
public void testDouble(){
// 0.060000000000000005System.out.println(0.05+0.01);// 0.5800000000000001System.out.println(1.0-0.42);// 401.49999999999994System.out.println(4.015*100);// 1.2329999999999999System.out.println(123.3/100);// 4.01 四舍五入保留两位System.out.println(Math.round(4.015*100)/100.0);
}
二:BigDecimal
BigDecimal有多种构造函数,常用的有2种,其中有一种不建议使用,就是double构造方式,建议使用String构造方式。
// 强制使用String的构造函数,double也有可能计算不太准确
// 原则是使用BigDecimal并且一定要用String来够造。
public BigDecimal(String val);
public BigDecimal(double val);
BigDecimal也定义了几个常用的值,0、1、10,静态的,可以通过类名直接引用BigDecimal.ZERO
public static final BigDecimal ZERO =zeroThroughTen[0];/*** The value 1, with a scale of 0.** @since 1.5*/public static final BigDecimal ONE =zeroThroughTen[1];/*** The value 10, with a scale of 0.** @since 1.5*/public static final BigDecimal TEN =zeroThroughTen[10];
三:工具类
由于构造方法要用String对应的构造方法,如果我们要做一个加法运算,需要先将两个浮点数转为String,然后够造成BigDecimal,在其中一个上调用add方法,传入另一个作为参数,然后把运算的结果(BigDecimal)再转换为浮点数。你能够忍受这么烦琐的过程吗?下面我们提供一个工具类来简化操作。
import java.math.BigDecimal;/*** 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精* 确的浮点数运算,包括加减乘除和四舍五入。*/
public class ArithUtil {
//默认除法运算精度private static final int DEF_DIV_SCALE = 10;/*** 提供精确的加法运算。* @param v1 被加数* @param v2 加数* @return 两个参数的和*/public static double add(double v1,double v2){
BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.add(b2).doubleValue();}/*** 提供精确的减法运算。* @param v1 被减数* @param v2 减数* @return 两个参数的差*/public static double sub(double v1,double v2){
BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.subtract(b2).doubleValue();}/*** 提供精确的乘法运算。* @param v1 被乘数* @param v2 乘数* @return 两个参数的积*/public static double mul(double v1,double v2){
BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.multiply(b2).doubleValue();}/*** 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到* 小数点以后10位,以后的数字四舍五入。* @param v1 被除数* @param v2 除数* @return 两个参数的商*/public static double div(double v1,double v2){
return div(v1,v2,DEF_DIV_SCALE);}/*** 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指* 定精度,以后的数字四舍五入。* @param v1 被除数* @param v2 除数* @param scale 表示表示需要精确到小数点以后几位。* @return 两个参数的商*/public static double div(double v1,double v2,int scale){
if(scale<0){
throw new IllegalArgumentException("The scale must be a positive integer or zero");}BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();}/*** 提供精确的小数位四舍五入处理。* @param v 需要四舍五入的数字* @param scale 小数点后保留几位* @return 四舍五入后的结果*/public static double round(double v,int scale){
if(scale<0){
throw new IllegalArgumentException("The scale must be a positive integer or zero");}BigDecimal b = new BigDecimal(Double.toString(v));BigDecimal one = new BigDecimal("1");return b.divide(one,scale, BigDecimal.ROUND_HALF_UP).doubleValue();}
}
测试
public void testBigDecimal(){
BigDecimal price = BigDecimal.ZERO;// 通常建议优先使用(String)构造函数BigDecimal amount = new BigDecimal("6.66");// 0.06System.out.println(ArithUtil.add(0.05, 0.01));// 0.58System.out.println(ArithUtil.sub(1.0, 0.42));// 401.5System.out.println(ArithUtil.mul(4.015, 100));// 1.233System.out.println(ArithUtil.div(123.3, 100));// 4.02System.out.println(ArithUtil.round(4.015, 2));// BigDecimal 比较大小使用compareTo方法// public int compareTo(BigDecimal val);}
6. 二分查找原理以及代码实现
通过遍历方式来查找元素所在的索引,数组中有多少个值就要循环多少次。
public static void main(String[] args) {
int value = 10;int[] array = {
2, 3, 5, 7, 9, 10, 11};int index = -1;for (int i = 0; i < array.length; i++) {
if (array[i] == value) {
index = i;break;}}// 5System.out.println(index);
}
二分查找
又称折半查找
, 用于对有序数组
快速查找某个值所在的下标。
实现原理是:将有序数组里元素从中间切割分成两部分,尝试将要查找的值与数组中间的那个值去比较,如果要找的值比数组中间的值小就去数组左边部分再次查找,如果要找的值比数组中间的值大就去数组右边部分再次寻找,这样每找一次就能排除掉一半的选项,最终找到值的索引或者值不在数组里面。
public static void main(String[] args) {
int[] array = {
2, 3, 5, 7, 9, 10, 11};// 5System.out.println(binarySearch(array, 10));// -1System.out.println(binarySearch(array, 12));}public static int binarySearch(int[] array, int value) {
// 最大索引int maxIndex = array.length - 1;// 最小索引int minIndex = 0;// 中间索引int middleIndex = (minIndex + maxIndex) / 2;while (array[middleIndex] != value) {
int middleValue = array[middleIndex];if (value > middleValue) {
// 要查找的值在后半部分minIndex = middleIndex + 1;} else if (value < middleValue) {
// 要查找的值在前半部分maxIndex = middleIndex - 1;}// 如果minIndex > maxIndex表示值不在数组中,没有查到用-1表示if (minIndex > maxIndex) {
return -1;}middleIndex = (minIndex + maxIndex) / 2;}return middleIndex;}
注意:快速查找只适用于有序数组,如果原来数组无序强制对数组排序然后再使用二分查找那么原来的元素的下标就会发生变化,导致查询到的下标值和原来无序的下标值不一样。
通过遍历方式我们需要循环数组长度的次数才能确定结果,而二分查找每次都过滤掉一半的选项,大大节省了循环的次数,而且当数组长度越大二分查找的次数就比遍历方式少很多,可以看到二分查找大大提高了查找的效率。
7.冒泡排序的原理分析及代码实现
排序:将一组数据按照固定规则(从小到大、从大到小)进行排列。
冒泡排序:一种排序方式,对要进行排序的数据中相邻的数据进行两两比较,将较大的数据放在后面,依次对所有数据进行操作,直至所有数据按要求排序完成。
- 如果有n个数据进行排序,总共需要比较n-1次。
- 每比较一轮,下一轮参数数据比较的个数就会少1,因为最大的已经排在最后面了就没必要再比较了。
循序渐进的实现方式:
public class Test {
public static void main(String[] args) {
int[] array = {
163, 171, 130, 81, 168};for (int i = 0; i < array.length - 1; i++) {
if (array[i] > array[i + 1]) {
int temp = array[i];array[i] = array[i + 1];array[i + 1] = temp;}}for (int i = 0; i < array.length - 1 - 1; i++) {
if (array[i] > array[i + 1]) {
int temp = array[i];array[i] = array[i + 1];array[i + 1] = temp;}}for (int i = 0; i < array.length - 1 - 2; i++) {
if (array[i] > array[i + 1]) {
int temp = array[i];array[i] = array[i + 1];array[i + 1] = temp;}}for (int i = 0; i < array.length - 1 - 3; i++) {
if (array[i] > array[i + 1]) {
int temp = array[i];array[i] = array[i + 1];array[i + 1] = temp;}}// [81, 130, 163, 168, 171]printArray(array);}public static void printArray(int[] array) {
StringBuilder sb = new StringBuilder("[");for (int i = 0; i < array.length; i++) {
sb.append(array[i]);if (i < array.length - 1) {
sb.append(", ");}}sb.append("]");System.out.println(sb.toString());}
}
public class Test {
public static void main(String[] args) {
int[] array = {
163, 171, 130, 81, 168};for (int i = 0; i < array.length - 1; i++) {
for (int j = 0; j < array.length - 1 - i; j++) {
if (array[j] > array[j + 1]) {
int temp = array[j];array[j] = array[j + 1];array[j + 1] = temp;}}}// [81, 130, 163, 168, 171]printArray(array);}public static void printArray(int[] array) {
StringBuilder sb = new StringBuilder("[");for (int i = 0; i < array.length; i++) {
sb.append(array[i]);if (i < array.length - 1) {
sb.append(", ");}}sb.append("]");System.out.println(sb.toString());}
}
冒泡排序简单说使用双重for循环,在内存循环中比较两个数的大小,如果前面的比后面的大两个就调换位置,如果前面的比后面的小保持不动,每一轮循环结束就能确定当前轮的最大值,然后把最大值放在每轮的最后,每循环一轮,内层循环就少循环一次,直到所有循环都结束,数组中的整个数据就从小到大排序了。
8. 递归的应用和注意事项
在方法的内部调用自己,这就是递归(recursion)
。
递归通常用于多次重复的计算场景中。
求1-100之间的和。
public static void main(String[] args) {
// 5050System.out.println(sum(100));
}public static int sum(int max) {
int sum = 0;for (int i = 1; i <= max; i++) {
sum += i;}return sum;
}
递归操作有点难理解,可以通过数学中的代入方法来理解。
public static void main(String[] args) {
// 5050System.out.println(sum(100));
}public static int sum(int n) {
if (n == 1) {
return 1;}return n + sum(n - 1);
}
斐波那契数列
,又称黄金分割数列
,指的是这样一个数列:0、1、1、2、3、5、8、13、21、……,在数学上,斐波纳契数列的定义:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2,n∈N*)即后面的一个数字是前面两个数字的和。
计算第n+1个斐波那契数列的值:
public static void main(String[] args) {
// 0, 1, 1, 2, 3, 5, 8// 13System.out.println(fib(7));
}public static int fib(int n) {
int a = 0;int b = 1;int c = 1;// f(0) = 0if (n == 0) {
return 0;} else if (n == 1 || n == 2) {
// f(1) = 1// f(2) = f(1) + f(0) = 1 + 0 = 1return 1;}// 要计算第n个数,只需要循环n-1次即可for (int i = 0; i < n - 1; i++) {
c = a + b;a = b;b = c;}return c;
}
public static void main(String[] args) {
// 0, 1, 1, 2, 3, 5, 8// 13System.out.println(fib(7));
}public static int fib(int n) {
if (n == 0) {
return 0;} else if (n == 1) {
return 1;}return fib(n - 1) + fib(n - 2);
}
一个正整数的阶乘(factorial)
是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘写作n!。亦即n!=1×2×3×...×(n-1)×n
。阶乘亦可以递归方式定义:0!=1
,n!=(n-1)!×n
。
public static void main(String[] args) {
// 4 * 3 * 2 * 1 = 24System.out.println(fac(4));
}public static int fac(int n) {
int result = 1;// n!=1×2×3×...×(n-1)×nfor (int i = 1; i <= n; i++) {
result *= i;}return result;
}
public static void main(String[] args) {
// 4 * 3 * 2 * 1 = 24System.out.println(fac(4));
}public static int fac(int n) {
if (n == 1) {
return 1;}return n * fac(n - 1);
}
递归注意事项:
递归必须有一个结束条件,一般都是if() { return }, 如果没有递归条件方法调用方法就会一直调用下去就成了一个死循环。
递归的特点:
- 代码简洁:更加简单的看出方法要实现的功能。
- 内存消耗大:在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储,递归次数过多容易造成栈溢出等,因此递归在实际工作中并不常用。
9. 快速排序原理以及代码实现
快速排序(Quick Sort)被称为20世纪十大算法之一,是迄今为止所有内排序算法中速度最快的一种。分治法:比大小,再分区。
实现原理:
- 从数组中取出一个值作为
基准值
,一般选第一个值作为基本值 。 - 分区:将大于等于基准值的元素放到右边,小于基准值的放在左边。
- 再对左右区间重复第二步,直到各区间只有一个数。
- pivot:从数组中取出一个值作为
基准值
,一般为low。 - high:高指针(索引),high指针不断的右往左走,寻找小于基准值的元素。
- low:低指针(索引), low指针不断的从左往右走,寻找大于基准值的元素。
排序原理:
- 从数组中跳出一个元素,称之为
基准(pivot)
,一般为low索引对应的元素。 - 使用while循环从右往左寻找比基准值小的元素,如果找到了就将high的值赋值给low,并记录寻找到的位置修改high 。
- 使用while循环从左往右寻找比基准值大的元素,如果找到了就将low的值赋值给high,并记录寻找到的位置修改low。
- 当low > high时,算是完成一轮排序,将基准值赋值给low位置,完成后左边的元素都比基准值小,右边的元素都比基准值大,这样就将左右两边分成梁。这个称为
分区(partition)
操作。 - 递归(recursive)。
- 递归的终止条件就是数组的长度小于等于1。
第一轮:确定中间值,将中间值放在中间位置,中间位置左边都是小于中间值,中间值右边都是大于中间值的。当low > high 就结束查找。
public class QuickSort {
public static void main(String[] args) {
int[] array = {
5, 2, 9, 3, 8, 4, 0, 1, 6, 7};quickSort(array);System.out.println(Arrays.toString(array));}public static void quickSort(int[] array) {
quickSort(array, 0, array.length - 1);}public static void quickSort(int[] array, int low, int high) {
if (low < high) {
// 找出位置int index = getIndex(array, low, high);// 左分区quickSort(array, low, index - 1);// 右分区quickSort(array, index + 1, high);}}private static int getIndex(int[] array, int low, int high) {
int pivot = array[low];while (low < high) {
// 从后往前找,找出第一个比基准值小的// 如果后面数组元素大于基准值证明该值不是需要的,继续往前寻找// 如果找到一个元素值小于基准值的证明则找到了while (array[high] >= pivot && low < high ) {
high--;}// 如果从后往前找到了,就把high位置上的值赋值给low位置上的值if (low < high) {
array[low] = array[high];low++;}// 从前往后找,找出第一个比基准值大的// 循环条件:如果元素比基准值小不满足条件,继续向前寻找while (low < high && array[low] < pivot) {
low++;}if (low < high) {
array[high] = array[low];high--;}}array[low] = pivot;System.out.println("index=" + low + ", array=" + Arrays.toString(array));return low;}
}
10. jar包的制作以及使用
10.1 使用命令制作
-
编写Java文件,注意文件中必须有main方法,并编译成class文件。
-
新建一个文件(胖文件),文件名为 MANIFEST.MF,文件内容包括版本号固定写死1.0,主类:main方法所在的类,带上包名。
Manifest-Version: 1.0
Main-Class: com.itheima.example.Main
- 打包
jar -cvfm xxx.jar MANIFEST.MF .
, .表示.jar文件要存放的目录,这里表示当前目录。 - 运行jar
java -jar xxx.jar
11.2 使用IDEA制作
- 编写Java文件(如ArrayUtils.java),并编译(菜单:Build - Recompile Xxx.jar),编译之后会在项目的根目录下有一个out目录。
public class ArrayUtils {
public static String array2String(int[] array) {
if (array == null) {
return "";}if (array.length == 0) {
return "[]";}StringBuilder sb = new StringBuilder("[");for (int i = 0; i < array.length; i++) {
sb.append(array[i]);if (i != array.length - 1) {
sb.append(", ");}}sb.append("]");return sb.toString();}public static void main(String[] args) {
int[] a = {
1, 2, 3};System.out.println(array2String(a));}
}
- Project Structure -> Artifacts - > + -> JAR -> from modules with dependencies -> 选择Main Class(main方法所在的类)
- 修改要导出的jar的文件名和导出位置
- Build -> Build Artifacts - > Build
11.3 如何使用.jar
Project Structure -> Libraries -> Java -> 选择xxx.jar文件。
11. Arrays类及其常用方法
Arrays:提供了一系列好用的操作数组的方法
public static void main(String[] args) {
int[] array = {
163, 171, 130, 81, 168};System.out.println(Arrays.toString(array));Arrays.sort(array);System.out.println(Arrays.toString(array));
}
工具类的设计思想:一般不提供公开的构造方法,调用方法时一般都是类名.方法名() 静态方式调用。
- 构造方法用private修饰
- 成员用public static修饰
12. 基本类型包装类
基本类型包装类就是为每种基本类型提供一个与之对应的类,类中定义一些常用的属性(最小值、最大值等)和操作基本类型的方法(比如基本类型与字符串的转换等)。
Integer
public static void main(String[] args) {
System.out.println(Integer.MIN_VALUE);System.out.println(Integer.MAX_VALUE);Integer num = Integer.valueOf(10);Integer quantity = Integer.valueOf("10");
}
int与String的相互转换
public static void main(String[] args) {
int num = 10;String str = num + "";String string = String.valueOf(num);Integer quantity = Integer.valueOf("10");int value = quantity.intValue();int number = Integer.parseInt("10");
}
字符串中数据排序
public class Test {
public static void main(String[] args) {
String num = "91 27 46 38 50";String[] nums = num.split(" ");int[] array = new int[nums.length];for (int i = 0; i < nums.length; i++) {
array[i] = Integer.parseInt(nums[i]);}Arrays.sort(array);printArray(array);}public static void printArray(int[] array) {
StringBuilder sb = new StringBuilder("");for (int i = 0; i < array.length; i++) {
sb.append(array[i] + " ");}System.out.println(sb.toString());}
}
13. 自动装箱和自动拆箱
- 装箱:把基本数据类型转换为对应的包装类类型。
- 拆箱:把包装类类型转为对应的基本数据类型。
当基本类型对应的包装类与基本类型进行计算时,包装类会自动调用对应的xxxValue()转为基本类型,然后再和基本类型相加。
public static void main(String[] args) {
Integer num = 1;int number = Integer.valueOf(1);// 手动拆箱int value = num.intValue() + number;// 自动拆箱// 自动装箱Integer temp = num + number;// NullPointerException 包装类型值如果为空与基本类型计算时会报空异常Integer foo = null;System.out.println(foo + 1);// 为了不报空异常,最好的办法是在使用前先判断一下是否为空,不为空再进行计算if (foo != null) {
System.out.println(foo + 1);}
}
14. Optional类以及使用
在Google Guava 中就有Optional,在Swift语言中也有这样类似的语法,在Swift中将可选值作为一种数据类型,地位和基本类型平齐平做,地位非常高。
关于of方法,现在好像很流行,就是提供一个static方法,方法名称叫of,方法的返回值返回当前类,并且把构造函数设置为私有private,用静态of方法来代替构造函数。
public class User {
private String username;private Integer age;private User() {
}public static User of() {
return new User();}private User(String username, Integer age) {
this.username = username;this.age = age;}public static User of(String username, Integer age) {
return new User(username, age);}
}
public static void main(String[] args) {
// Optional类已经成为Java 8类库的一部分,在Guava中早就有了,可能Oracle是直接拿来使用了// Optional用来解决空指针异常,使代码更加严谨,防止因为空指针NullPointerException对代码造成影响String msg = "hello";Optional<String> optional = Optional.of(msg);// 判断是否有值,不为空boolean present = optional.isPresent();// 如果有值,则返回值,如果等于空则抛异常String value = optional.get();// 如果为空,返回else指定的值String hi = optional.orElse("hi");// 如果值不为空,就执行Lambda表达式optional.ifPresent(opt -> System.out.println(opt));
}
15. ProcessBuilder类以及使用
ProcessBuilder是J2SE 1.5在java.lang中新添加的一个新类, 用于创建操作系统进程,它提供一种启动和管理进程(也就是应用程序)的方法。在J2SE 1.5之前,都是由Process类处来实现进程的控制管理。简单的说ProcessBuilder是用来执行Shell命令的。
- ProcessBuilder(String… command) :构造参数接收一个可变参数,第一个参数为命令名称,后面的参数为命令本身的参数。
- start() :开始执行命令。
- Process#getInputStream() : 获取命令执行的标准输出。
- Process#getErrorStream():获取命令执行的标准错误。
- ProcessBuilder#directory(File file): 设置命令执行的当前目录。
- ProcessBuilder.redirectErrorStream(boolean):是否将标准输出和错误输出合并到inputStream中。
- ProcessBuilder.redirectOutput(ProcessBuilder.Redirect.appendTo(File file)): 是否想输出写到文件中。
- ProcessBuilder#environment():获取命令所执行的环境变量,可以获取也可以进行修改。
public static void main(String[] args) throws Exception {
// Shell 操作工具类ProcessBuilder processBuilder = new ProcessBuilder("ls", "-l", "/Users/mengday");Process process = processBuilder.start();InputStream in = process.getInputStream();byte[] buffer = new byte[1024];StringBuffer sb = new StringBuffer();while (in.read(buffer) != -1) {
sb.append(new String(buffer, "utf-8"));sb.append("\n");}System.out.println(sb.toString());System.out.println("-----------------------------------");InputStream errorStream = process.getErrorStream();BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorStream));String errorLine = null;while ((errorLine = errorReader.readLine()) != null) {
System.out.println(errorLine);}
}
public static void main(String[] args) throws Exception {
ProcessBuilder processBuilder = new ProcessBuilder("ls", "-l");processBuilder.directory(new File("/Users/mengday/Temp"));processBuilder.redirectErrorStream(true);processBuilder.redirectOutput(ProcessBuilder.Redirect.appendTo(new File("/Users/mengday/Temp/log")));Map<String, String> environment = processBuilder.environment();System.out.println("environment=" + environment);processBuilder.start();
}
16. 日期Date类型以及常用方法
Date日期类表示一个特定的时间,精确到毫秒。
public static void main(String[] args) {
// Date 重写了toString()Date date = new Date();System.out.println(date);// Date是从1970年1月1日0时0分0秒开始的,但是Date默认使用的是标准时间// 中国是东八区 所以 +8个小时int oneHour = 60 * 60 * 1000;Date time = new Date(oneHour);System.out.println(time);
}
日期类的时间从为什么是从1970年1月1日
Date 常用方法
17. 日期格式化 SimpleDateFormat
SimpleDateFormat是一个日期格式化的工具类,用于对日期Date对象转成日期字符串String,或者日期字符串String转为日期对象Date。
public static void main(String[] args) throws ParseException {
Date now = new Date();SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");String nowString = format.format(now);System.out.println(nowString);String dateStr = "2020年7月31日 10:20:30";SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");Date nowDate = dateFormat.parse(dateStr);System.out.println(nowDate);
}
日期工具类
public class DateUtils {
private DateUtils() {
}public static String dateToString(Date date, String pattern) {
SimpleDateFormat format = new SimpleDateFormat(pattern);return format.format(date);}public static Date string2date(String date, String pattern) throws ParseException {
SimpleDateFormat format = new SimpleDateFormat(pattern);return format.parse(date);}public static void main(String[] args) throws ParseException {
String str = DateUtils.dateToString(new Date(), "yyyy-MM-dd hh:mm:ss");System.out.println(str);Date date = DateUtils.string2date("2020-07-31 10:36:13", "yyyy-MM-dd hh:mm:ss");System.out.println(date);}
}
18. 日历Calendar类的使用
Calendar为某一时刻和一组日历字段之间的转换提供了一些方法,并为操作日历字段提供了一些方法。
Calendar提供了一个类方法getInstance用于获取Calendar对象,器日历字段已经使用当前日期和时间初始化。
public static void main(String[] args) throws ParseException {
Calendar calendar = Calendar.getInstance();int year = calendar.get(Calendar.YEAR);int month = calendar.get(Calendar.MONTH) + 1;int date = calendar.get(Calendar.DATE);System.out.println(year + "\t" + month + "\t" + date);}
Calendar常用方法
public static void main(String[] args) throws ParseException {
Calendar calendar = Calendar.getInstance();int year = calendar.get(Calendar.YEAR);// 年是从0开始的int month = calendar.get(Calendar.MONTH) + 1;int date = calendar.get(Calendar.DATE);System.out.println(year + "\t" + month + "\t" + date);// 对年字段加3年calendar.add(Calendar.YEAR, 3);// 5天前calendar.add(Calendar.DATE , -5);System.out.println(year + "\t" + month + "\t" + date);calendar.set(2012, 8, 10);
}
二月天
public static void main(String[] args) throws ParseException {
Scanner scanner = new Scanner(System.in);System.out.print("请输入年:");int year = scanner.nextInt();Calendar calendar = Calendar.getInstance();calendar.set(year, 2, 1);calendar.add(Calendar.DATE, -1);int date = calendar.get(Calendar.DATE);System.out.println(year + " 年2月份有 " + date + " 天");
}
19. JDK8新增的日期Date API(LocalDateTime、LocalDate、LocalTime、Instant、Period、Duration)
20. NumberFormat类以及使用
数字格式化就是将数字(整数、小数)转为字符串String,在转换的过程中可能会对小数四舍五入、位数不够可能使用0来填充等。
- static NumberFormat getInstance() 获取当前默认语言环境的一个数字格式实例。
- static NumberFormat getCurrencyInstance() 获取货币数字格式实例,默认是当前语言环境中国货币¥,可以通过Locale.US设定美国货币符号 $。
- static NumberFormat getPercentInstance() 获取百分比数字格式实例。
void setMinimumIntegerDigits(int newValue) : 设置整数部分最小长度,如果长度不够就在最前面填充0.
public static void main(String[] args) {
NumberFormat format = NumberFormat.getInstance();format.setMinimumIntegerDigits(2);// 123System.out.println(format.format(123));// 03System.out.println(format.format(3));
}
void setMaximumIntegerDigits(int newValue) : 设置整数部分最大长度,超过最大长度将保留后面的舍弃高位的数字。
public static void main(String[] args) {
NumberFormat format = NumberFormat.getInstance();format.setMaximumIntegerDigits(2);// 23System.out.println(format.format(123));// 3System.out.println(format.format(3));
}
void setMinimumFractionDigits(int newValue) :设置小数部分最小长度,长度不够用0占位。
public static void main(String[] args) {
NumberFormat format = NumberFormat.getInstance();format.setMinimumFractionDigits(2);// 123.00System.out.println(format.format(123));// 3.50System.out.println(format.format(3.5));// 1.68System.out.println(format.format(1.68));
}
void setMaximumFractionDigits(int newValue): 设置小数部分最大长度,多余的长度会四舍五入。
public static void main(String[] args) {
NumberFormat format = NumberFormat.getInstance();format.setMaximumFractionDigits(2);// 123System.out.println(format.format(123));// 3.5System.out.println(format.format(3.5));// 1.69System.out.println(format.format(1.688));
}
货币格式化
public static void main(String[] args) {
NumberFormat format = NumberFormat.getCurrencyInstance();// ¥1,688.17System.out.println(format.format(1688.168));NumberFormat format2 = NumberFormat.getCurrencyInstance(Locale.US);// $1,688.17System.out.println(format2.format(1688.168));
}
百分比格式化
public static void main(String[] args) {
NumberFormat format = NumberFormat.getPercentInstance();format.setMaximumFractionDigits(2);// 16.17%System.out.println(format.format(0.16168));
}
20.1 DecimalFormat
- “0”——表示一位数值,如没有,显示0。
- “#”——表示任意位数的整数。如没有,则不显示。在小数点位使用,只表示一位小数,超出部分四舍五入。
- “#”:无小数,小数部分四舍五入。
- “.#”:整数部分不变,一位小数,四舍五入。
- “.##”:整数部分不变,二位小数,四舍五入。
- “.”——表示小数点。
- “,”——与模式“0”一起使用,表示逗号。
public static void main(String[] args) {
DecimalFormat format = new DecimalFormat("0000.000");// 0123.457System.out.println(format.format(123.456789));DecimalFormat format2 = new DecimalFormat("#");// 1235System.out.println(format2.format(1234.56789));DecimalFormat format3 = new DecimalFormat(".####");// 168.16System.out.println(format3.format(168.16));// 168.1689System.out.println(format3.format(168.16888));// 注意“,”不能放在小数部分DecimalFormat format4 = new DecimalFormat("0000,0000.00");// 1234,5678.17System.out.println(format4.format(12345678.168));
}