项目自学目录6
关于Future的深度解析
Future表示一个任务的周期,并提供了相应的方法来判断是否已经完成或者取消,以及获取任务的结果和取消任务
Future是一个接口,是无法生成一个实例的,所以又有了FutureTask。
Future中有5个方法
1、cancel():取消一个任务,并返回取消结果。参数表示是否中断线程
2、isCancelled():任务是否取消成功
3、isDone():判断当前任务是否执行完毕,包括正常执行完毕、执行异常或者任务取消
4、get():获取任务执行结果,任务结束之前会阻塞
5、get(long count,TimeUnit):在指定时间内尝试获取执行结果。若超时则抛出超时异常
ThreadPoolExecutor提供了三个方法,来获取返回值
FutureTask是一个具体的实现类,ThreadPoolExecutor的submit方法返回的就是一个Future的实现,这个实现就是FutureTask的一个具体实例,FutureTask帮助实现了具体的任务执行,以及和Future接口中的get方法的关联。
futureTask.get()执行时如果该任务已经执行完了则直接返回执行结果,如果没有执行完则线程会阻塞在这里,直至任务执行完毕。还可以用get(long timeout, TimeUnit unit)来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。
总结
总的来说Future模式的思想就是在子线程进行执行的时候,主线程不阻塞继续执行。等到主线程需要子线程的结果的时候再去获取子线程的结果(此时子线程没有执行完成的话就会阻塞直至执行完成)。主线程还可以根据一定的业务逻辑去判断是否要取消执行子线程,还可以设置一个超时时间。若阻塞时间超过了超时时间子线程仍然没有执行完成的话,可以直接返回null。
DateFormatUtils.format(date, pattern)日期格式化的优雅写法
import org.apache.commons.lang3.time.DateFormatUtils;
引入依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.13.0</version>
</dependency>
前面传个new Date()的参数,后面传个 “yyyy-MM-dd”的参数
把JSON转为hashmap
注意要用alibaba.fastjson而不是hutool的json
import com.alibaba.fastjson.JSON;
不过要注意,他的key好像是转为string了,而value则智能的转为数字了。
编译优化?— 将成员变量转为局部变量
原来我是用成员变量map直接去put,但是他install到别的文件后,新增了var10000这个局部变量。
当然这个map不能直接声明在beforeCreateOfd()里,因为下面还有个函数也用到了map
BigDecimal再探
BigDecimal要用BigDecimal(String)构造器创建对象才有意义
其他的如BigDecimal b = new BigDecimal(1)这种,还是会发生精度丢失的问题。
源码
public class BigDecimal extends Number implements Comparable<BigDecimal> {
private final BigInteger intVal;
private final int scale;
}
比较BigDecimal要用compareTo
在比较两个BigDecimal
的值是否相等时,要特别注意,使用equals()
方法不但要求两个BigDecimal
的值相等,还要求它们的scale()
相等.
必须使用compareTo()
方法来比较,它根据两个值的大小分别返回负数、正数和0
,分别表示小于、大于和等于。
一些和小数有关的方法
BigDecimal
用scale()
表示小数位数
通过BigDecimal
的stripTrailingZeros()
方法,可以将一个BigDecimal
格式化为一个相等的,但去掉了末尾0的BigDecimal
:
如果他本身的scale()是大于0的数字,那还好。去掉末尾的0;如果是一个整数,则直接变为科学计数法了。
@Test
public void test6(){
BigDecimal d1 = new BigDecimal("123.4500");
BigDecimal d2 = d1.stripTrailingZeros();
System.out.println(d1.scale()); // 4
System.out.println(d2.scale()); // 2,因为去掉了00
BigDecimal d3 = new BigDecimal("1234500");
BigDecimal d4 = d3.stripTrailingZeros();
System.out.println(d3.scale()); // 0
System.out.println(d4.scale()); // -2
System.out.println(d1); //123.4500
System.out.println(d2); //123.45
System.out.println(d3); //1234500
System.out.println(d4); //1.2345E+6
BigDecimal d5=new BigDecimal("1230.00");
BigDecimal d6=d5.stripTrailingZeros();
System.out.println(d5.scale()); //2
System.out.println(d5); //1230.00
System.out.println(d6.scale()); //-1
System.out.println(d6); //1.23E+3
}
设置小数的精度
可以对一个BigDecimal
设置它的scale
,如果精度比原始值低,那么按照指定的方法进行四舍五入或者直接截断:
BigDecimal d1 = new BigDecimal("123.456789");
BigDecimal d2 = d1.setScale(4, RoundingMode.HALF_UP); // 四舍五入,123.4568
BigDecimal d3 = d1.setScale(4, RoundingMode.DOWN); // 直接截断,123.4567
一些BigDecimal的除法相关
对BigDecimal
做加、减、乘时,精度不会丢失,但是做除法时,存在无法除尽的情况,这时,就必须指定精度以及如何进行截断:
BigDecimal d1 = new BigDecimal("123.456");
BigDecimal d2 = new BigDecimal("23.456789");
BigDecimal d3 = d1.divide(d2, 10, RoundingMode.HALF_UP); // 保留10位小数并四舍五入
BigDecimal d4 = d1.divide(d2); // 报错:ArithmeticException,因为除不尽
调用divideAndRemainder()
方法时,返回的数组包含两个BigDecimal
,分别是商和余数,其中商总是整数,余数不会大于除数。我们可以利用这个方法判断两个BigDecimal
是否是整数倍数
BigDecimal n = new BigDecimal("12.75");
BigDecimal m = new BigDecimal("0.15");
BigDecimal[] dr = n.divideAndRemainder(m);
if (dr[1].signum() == 0) {
// n是m的整数倍
}
dr[0] 为 商,恒为整数, dr[1]为余数,其很可能为小数。
BigDecimal的3个toString方法的区别
BigDecimal类有3个toString方法,分别是toEngineeringString、toPlainString和toString,
从BigDecimal的注释中可以看到这3个方法的区别:
toEngineeringString:有必要时使用工程计数法。工程记数法是一种工程计算中经常使用的记录数字的方法,与科学技术法类似,但要求10的幂必须是3的倍数
toPlainString:不使用任何指数
toString:有必要时使用科学计数法
不使用指数 | 科学记数法 | 工程记数法 |
---|---|---|
2700 | 2.7 × 10³ | 2.7 × 10³ |
27000 | 2.7 × 10⁴ | 27 × 10³ |
270000 | 2.7 × 10⁵ | 270 × 10³ |
2700000 | 2.7 × 10⁶ | 2.7 × 10⁶ |
严格的只保留两位小数
if(formatDecimal.scale()<=2){
DecimalFormat decimalFormat = new DecimalFormat("0.00");
resDecimal = decimalFormat.format(formatDecimal);
}
DecimalFormat format方法:
1:new DecimalFormat(“00.000”).format(pi) //结果:03.142
2:new DecimalFormat(“##.###”).format(pi) //结果:3.142
都是对pi进行格式化,但第一个的结果是03.142,第二个的结果是3.142
这是什么原因呢?
0和#都是占位符,但在不同的地方,作用不一样。下面对他们做了具体的比较。
希望对大家有所帮助。
0:
比实际数字的位数多,不足的地方用0补上。
new DecimalFormat(“00.00”).format(3.14) //结果:03.14
new DecimalFormat(“0.000”).format(3.14) //结果: 3.140
new DecimalFormat(“00.000”).format(3.14) //结果:03.140
比实际数字的位数少:整数部分不改动,小数部分,四舍五入
new DecimalFormat(“0.000”).format(13.146) //结果:13.146
new DecimalFormat(“00.00”).format(13.146) //结果:13.15
new DecimalFormat(“0.00”).format(13.146) //结果:13.15
#:
比实际数字的位数多,不变。
new DecimalFormat(“##.##”).format(3.14) //结果:3.14
new DecimalFormat(“#.###”).format(3.14) //结果: 3.14
new DecimalFormat(“##.###”).format(3.14) //结果:3.14
比实际数字的位数少:整数部分不改动,小数部分,四舍五入
new DecimalFormat(“#.###”).format(13.146) //结果:13.146
new DecimalFormat(“##.##”).format(13.146) //结果:13.15
new DecimalFormat(“#.##”).format(13.146) //结果:13.15
在set属性内容的时候,推荐多使用三目运算符,以保证不set进Null值
domain.setNote(null==vatInvoicedQueryVO.getMemo()?"":vatInvoicedQueryVO.getMemo());
如果为null就set进去一个空字符串,反正后面也会用notBlank做校验。
StringUtils.nvl
自己封装的,为null则返回默认值
public static <T> T nvl(T value, T defaultValue) {
return value != null ? value : defaultValue;
}
当在 try
块或 catch
块中遇到 return
语句时,finally
语句块将在方法返回之前被执行。
同时,
注意:不要在 finally 语句块中使用 return! 当 try 语句和 finally 语句中都有 return 语句时,try 语句块中的 return 语句会被忽略。这是因为 try 语句中的 return 返回值会先被暂存在一个本地变量中,当执行到 finally 语句中的 return 之后,这个本地变量的值就变为了 finally 语句中的 return 返回值。
在某些情况下,finally 中的代码不会被执行。
就比如说 finally 之前虚拟机被终止运行的话,finally 中的代码就不会被执行。以及程序所在的线程死亡或者关闭CPU,也会导致finally块的代码不会被执行。
线程工厂的命名
// ThreadPoolExecutor(核心线程池大小, 最大线程池大小, 线程最大空闲时间, 时间单位, 线程等待队列, 拒绝策略)
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("Job-InvStocSync-pool-%d").build();
ExecutorService threadPool = new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.CallerRunsPolicy());
swap函数在Java里的书写
第一种,借助数组
public static void swap(int[] nums,int a,int b){
int temp=nums[a];
nums[a]=nums[b];
nums[b]=temp;
}
第二种,借助类
写一个类似于Integer的类,里面封装一个int的属性。这样swap传入的就是对象的引用了,就可以修改Int的属性值了。
第三种
public static int swap(int a, int b) { // usage: y = swap(x, x=y);
return a;
}
使用方法就是y = swap(x, x=y);