项目自学记录6


项目自学目录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,分别表示小于、大于和等于。

一些和小数有关的方法

BigDecimalscale()表示小数位数

通过BigDecimalstripTrailingZeros()方法,可以将一个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);


文章作者: 爱敲代码の鱼儿
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 爱敲代码の鱼儿 !
  目录