• [技术干货] Java8使用stream流给List<Map<String,Object>>分组(多字段key)-转载
     Java8使用stream流给List<Map<String,Object>>根据字段key分组 一、项目场景: 从已得到的List集合中,根据某一元素(这里指map的key)进行分组,筛选出需要的数据。 如果是SQL的话则使用group by直接实现,代码的方式则如下: 使用到stream流的Collectors.groupingBy()方法。  二、代码实现 1、首先将数据add封装到List中,完成数据准备。  //groupList用于库-表分组的list,减少jdbc连接时间 List<Map<String,Object>> groupList = new ArrayList<>(); Map<String,Object> map1 = new HashMap<>(); map.put("name","张三"); map.put("age",20); Map<String,Object> map2 = new HashMap<>(); map.put("name","李四"); map.put("age",20); //excel每行的值存入集合中 groupList.add(map1); groupList.add(map2); 2、然后按照name属性进行分组(单字段),使用stream流分组  //分组判断,stream流 Map<String, List<Map<String, Object>>> listMap =         groupList.stream().collect(             Collectors.groupingBy(item -> item.get("name").toString())         ); ··按照name,age属性进行分组(多字段),使用stream流分组  //分组判断,stream流 Map<String, List<Map<String, Object>>> listMap =         groupList.stream().collect(             Collectors.groupingBy(item -> item.get("name").toString()+"|"+item.get("age"))         ); 3、遍历结果,输出查看 得到Map<String, List<Map<String, Object>>>, key是你分组的字段,value分组下对应的值。 也就是group by的效果。  for (String groupKey : listMap.keySet()) {     //分组key     System.out.println("分组Key: "+groupKey);     System.out.println("分组Key的value: "+listMap.get("groupKey")); } ———————————————— 版权声明:本文为CSDN博主「Lin'ZT」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_43920527/article/details/129820467 
  • [技术干货] RestTemplate 中post请求,默认Content-Type类型及修改请求类型
    默认情况下,Spring的RestTemplate发送POST请求时,请求Content-Type类型是application/json。如果要将请求的Content-Type设置为form-data,可以使用MultiValueMap,并使用postForObject方法发送POST请求。示例如下:import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; public class RestClient { private RestTemplate restTemplate; public RestClient() { this.restTemplate = new RestTemplate(); } public void doPostRequest() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); body.add("key1", "value1"); body.add("key2", "value2"); HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers); String url = "http://your-api-url"; String response = restTemplate.postForObject(url, requestEntity, String.class); System.out.println(response); } }复制在上面的代码中,我们首先创建了一个HttpHeaders对象,将ContentType设置为MediaType.MULTIPART_FORM_DATA,表示该请求是form-data类型。然后,我们使用LinkedMultiValueMap将请求的参数添加到请求体中。最后,我们使用postForObject方法向API发送POST请求,并传入url、requestEntity和返回值类型。MultiValueMap是一个类似于Map的数据结构,它在键-值对中允许存在多个值。在Java语言中,Spring框架中的org.springframework.util.MultiValueMap接口定义了一个具有此特性的映射表数据类型。对于普通的Map接口来说,在一个键(key)下只能包含一个值(value),而MultiValueMap可以容纳多个值,例如:MultiValueMap<String, String> multiValueMap = new LinkedMultiValueMap<>(); multiValueMap.add("name", "张三"); multiValueMap.add("hobby", "篮球"); multiValueMap.add("hobby", "足球"); System.out.println(multiValueMap);复制上面代码中我们使用LinkedMultiValueMap创建了一个MultiValueMap类型的对象,并向其添加了键为"name"和"hobby"的数据,其中"hobby"这个键下有两个值。输出结果为:{name=[张三], hobby=[篮球, 足球]}复制该数据结构主要用于解析HTML表单提交的数据或HTTP请求参数,特别是当前端页面的某个表单字段需要提交一个列表或数组时。使用MultiValueMap则无需手动处理重复键值,可以更方便地进行数据管理和交换。Spring框架中的RestTemplate类,就利用了MultiValueMap实现了HTTP请求参数的传递和解析。其他一些框架和库,如Jackson、Gson等也支持将JSON转换为MultiValueMap,并方便地将其转换为Java对象。
  • [技术干货] java中RestTemplate和HttpClient的区别
    RestTemplate 和 HttpClient 都是Java中用于发送HTTP请求的工具之一,但它们在实现上有些不同。HttpClient 是 Apache 开源组织提供的一个URL客户端库。它提供了HTTP协议的客户端实现。可以通过 HttpPost,HttpGet,HttpPut等类实现相应的 HTTP 请求,同时 HttpClient 提供了 Header,Response等信息的处理。使用 HttpClient 可以控制HTTP请求与响应行为的各个方面,比如连接超时,重定向,异常处理等。而 RestTemplate 是 Spring Framework 提供的模板类,用于简化 HTTP 请求与响应处理。它是基于 HttpMessageConverter 实现的,可以将 HTTP 消息转换为 Java 对象和将 Java 对象转换为 HTTP 消息。它支持 GET,POST,PUT,DELETE,PATCH 等 HTTP 方法。使用 RestTemplate 可以更加方便地进行 HTTP 请求,同时它也提供了自定义的拦截器、错误处理和重试机制等功能。相比较而言,RestTemplate 更适合于集成Spring框架的项目中使用,其简化代码结构,生产力更高,可进行更丰富的配置和扩展;而 HttpClient 更灵活,可适用于所有 Java 项目,它更底层,需要程序员自己管理和回收资源。在选择使用哪种工具时,可以根据实际项目情况来进行取舍。如果你已经使用了Spring框架,你可以考虑使用RestTemplate ,它将提供更好的集成和默认配置。如果你需要更灵活、底层控制程度更高的HTTP请求库, 你可能更愿意选择 HttpClient 。
  • [专题汇总] 速进,一帖打尽2023年5月CodeArts板块技术干货合集贴。
     大家好,这个月给大家带来的是5月份codeArts板块技术干货合集贴分享。希望可以给大家带来帮助,快捷便利的获取到自己想要的技术干货。 1.centos下安装redis6.0.2方法及踩坑记录。 https://bbs.huaweicloud.com/forum/thread-0236120881445478099-1-1.html  2.64位MFC调用32位DLL https://bbs.huaweicloud.com/forum/thread-0228120819107276100-1-1.html  3.用js+html,全网最火build出爱心【转】 https://bbs.huaweicloud.com/forum/thread-0236120798795045092-1-1.html  4.Django权限系统auth模块用法解读【转】 https://bbs.huaweicloud.com/forum/thread-0248120796948452094-1-1.html  5.Django日志logging的配置和自定义添加方式【转】 https://bbs.huaweicloud.com/forum/thread-0248120796668399093-1-1.html  6.Django如何利用uwsgi和nginx修改代码自动重启【转】 https://bbs.huaweicloud.com/forum/thread-0228120794336186093-1-1.html  7.Python实现监控一个程序的运行情况【转】 https://bbs.huaweicloud.com/forum/thread-02115120793876180082-1-1.html  8.使用Python和Scrapy实现抓取网站数据【转】 https://bbs.huaweicloud.com/forum/thread-0243120793550271100-1-1.html  9.浅谈一下关于Python对XML的解析【转】 https://bbs.huaweicloud.com/forum/thread-0260120793358226074-1-1.html  10.如何用python多次调用exe文件运行不同的结果【转】 https://bbs.huaweicloud.com/forum/thread-0264120793008226093-1-1.html  11.django和vue互传图片并进行处理和展示【转】 https://bbs.huaweicloud.com/forum/thread-0228120792806281092-1-1.html  12.django python 获取当天日期的方法【转】 https://bbs.huaweicloud.com/forum/thread-0243120792719244099-1-1.html  13.python之关于数组和列表的区别及说明【转】 https://bbs.huaweicloud.com/forum/thread-0243120792501298098-1-1.html  14.python数组和矩阵的用法解读【转】 https://bbs.huaweicloud.com/forum/thread-0260120792197826073-1-1.html  15.Python利用wxPython实现长文本处理【转】 https://bbs.huaweicloud.com/forum/thread-02115120792101273081-1-1.html  16.django如何计算两个TimeField的时差【转】 https://bbs.huaweicloud.com/forum/thread-0236120792022558090-1-1.html      17.python连接kafka加载数据的项目实践【转】 https://bbs.huaweicloud.com/forum/thread-0243120791900417097-1-1.html  18.数据翻译——Easy_Trans的简单使用 https://bbs.huaweicloud.com/forum/thread-0236120706211297083-1-1.html  19.vue如何使用print-nb库来实现打印功能 https://bbs.huaweicloud.com/forum/thread-02115120450806805064-1-1.html  20.如何使用Vue.js来实现打印功能 https://bbs.huaweicloud.com/forum/thread-0264120450582740073-1-1.html  21.使用Java Cron表达式实现定时器 https://bbs.huaweicloud.com/forum/thread-0243120448768906076-1-1.html  22.JDK8 Stream 操作 https://bbs.huaweicloud.com/forum/thread-0248120389213456072-1-1.html  23.Springboot在有锁的情况下如何正确使用事务 https://bbs.huaweicloud.com/forum/thread-0228120388866643073-1-1.html  24.免费漂亮的Java图形验证码 https://bbs.huaweicloud.com/forum/thread-02115120388590161062-1-1.html  25.Vue-CLI 3.0中配置production gzip https://bbs.huaweicloud.com/forum/thread-02115120388359055061-1-1.html 
  • NIO介绍
     Java NIO(New IO)是Java 1.4引入的一项新技术,它提供了一种高效、灵活的I/O处理方式。相比于传统的I/O模型,NIO采用了基于缓冲区、通道和选择器等概念的方式来实现高效的数据传输。  在传统的I/O模型中,每个I/O操作都需要创建一个新的连接、读取或写入数据等,这些操作不仅耗时长,而且容易出现资源浪费的情况。而NIO则通过使用缓冲区来存储输入输出的数据,并通过通道进行数据的传输,从而大大提高了I/O效率。  在Java NIO中,通道(Channel)是最基本的I/O组件之一。通道可以分为字节通道(Byte Channel)、字符通道(Char Channel)、文件通道(File Channel)等多种类型,每种类型的通道都有其特定的读写方式和适用场景。例如,字节通道适用于网络通信、文件读写等场景;字符通道适用于文本数据的读写等场景。  除了通道之外,Java NIO还提供了选择器(Selector)的概念。选择器用于监听多个通道的状态变化,当某个通道就绪时,选择器会通知应用程序进行相应的读写操作。这种方式可以同时监听多个通道的状态变化,从而避免了频繁地轮询和创建连接等操作,提高了系统的性能和吞吐量。  Java NIO还提供了Buffer、ChannelHandler等重要的概念。Buffer是用于存储输入输出数据的缓存区,可以提高数据传输的效率;ChannelHandler则是用于处理通道事件的接口,可以通过实现该接口来处理通道就绪、异常等事件。  总之,Java NIO是一种高效、灵活的I/O处理方式,它可以大大提高系统的性能和吞吐量。对于需要高效数据传输的应用程序来说,Java NIO是一个非常值得学习和使用的技术。  Selector、Poll和Epoll都是Java NIO中用于处理I/O事件的机制,它们都可以提高系统的性能和吞吐量。下面是它们的介绍和区别:    1. Selector Selector是Java NIO中最常用的I/O事件选择器,它可以同时监听多个通道的状态变化,并在通道状态发生变化时通知应用程序进行相应的读写操作。Selector的使用需要创建一个Selector对象,然后通过调用register()方法将需要监听的Channel注册到Selector上。当某个Channel就绪时,Selector会返回对应的事件,应用程序可以通过调用select()方法来等待事件的发生。Selector的优点是可以同时监听多个通道的状态变化,适用于高并发的场景;缺点是它的使用比较复杂,需要手动管理注册和注销等操作。    2. Poll Poll也是Java NIO中的一种I/O事件选择器,它与Selector类似,也可以同时监听多个通道的状态变化。不同的是,Poll使用的是轮询的方式来检查通道的状态变化,而Selector则是使用回调函数的方式来处理事件。Poll的优点是使用比较简单,适合于低并发的场景;缺点是它的性能比Selector差一些。    3. Epoll Epoll是Java NIO中的最新版本,它是一种高效的I/O事件选择器,可以实现快速的事件响应和高效的系统利用率。Epoll使用基于事件驱动的方式来处理I/O事件,当某个Channel就绪时,Epoll会立即返回对应的事件,而不需要像Selector和Poll那样轮询或回调函数。Epoll的优点是性能比Selector和Poll好很多,适用于高并发的场景;缺点是它的使用比较复杂,需要手动管理注册和注销等操作。  总之,Selector、Poll和Epoll都是Java NIO中用于处理I/O事件的机制,它们各有优缺点,适用于不同的场景。在选择使用哪种机制时,需要根据具体的应用场景来进行选择。 
  • [其他] java线程同步CoutDownLatch、CylicBarrier、Semsphore
     CountDownLatchCountDownLatch是Java并发包(java.util.concurrent)中的一种同步工具,它允许一个或多个线程等待其他线程完成任务后再执行。CountDownLatch通常用于在多线程环境下协调任务的执行顺序。  CountDownLatch的基本用法如下:    1. 创建一个CountDownLatch实例:  import java.util.concurrent.CountDownLatch;  public class CountDownLatchExample {      public static void main(String[] args) throws InterruptedException {         CountDownLatch latch = new CountDownLatch(3); // 初始化CountDownLatch,需要3个线程调用countDown()方法          Thread thread1 = new Thread(new Task(latch, "Thread 1"));         Thread thread2 = new Thread(new Task(latch, "Thread 2"));         Thread thread3 = new Thread(new Task(latch, "Thread 3"));          thread1.start();         thread2.start();         thread3.start();     } }  class Task implements Runnable {      private final CountDownLatch latch;     private final String name;      public Task(CountDownLatch latch, String name) {         this.latch = latch;         this.name = name;     }      @Override     public void run() {         try {             System.out.println("Task " + name + " is running");             Thread.sleep(1000); // 模拟任务执行时间             System.out.println("Task " + name + " completed");             latch.countDown(); // 当计数器减至0时,所有等待的线程将被唤醒         } catch (InterruptedException e) {             e.printStackTrace();         }     } } 在这个示例中,我们创建了一个名为CountDownLatchExample的类。main()方法中,我们创建了一个CountDownLatch实例,并为3个线程分别分配了任务。然后,我们启动这3个线程。每个线程在完成任务后调用CountDownLatch的countDown()方法,当计数器减至0时,主线程将被唤醒。 CyclicBarrier CyclicBarrier是Java并发包(java.util.concurrent)中的一种同步工具,它允许一组线程在达到某个共享状态时一起阻塞。CyclicBarrier主要用于协调多个线程之间的顺序执行或同步。  CyclicBarrier的基本用法如下:    1. 创建一个CyclicBarrier实例:  import java.util.concurrent.CyclicBarrier;  public class CyclicBarrierExample {      public static void main(String[] args) throws InterruptedException {         CyclicBarrier barrier = new CyclicBarrier(3); // 初始化CyclicBarrier,需要3个线程调用await()方法          Thread thread1 = new Thread(new Task(barrier, "Thread 1"));         Thread thread2 = new Thread(new Task(barrier, "Thread 2"));         Thread thread3 = new Thread(new Task(barrier, "Thread 3"));          thread1.start();         thread2.start();         thread3.start();     } }  class Task implements Runnable {      private final CyclicBarrier barrier;     private final String name;      public Task(CyclicBarrier barrier, String name) {         this.barrier = barrier;         this.name = name;     }      @Override     public void run() {         try {             System.out.println("Task " + name + " is running");             Thread.sleep(1000); // 模拟任务执行时间             System.out.println("Task " + name + " completed");             barrier.await(); // 当所有线程都到达屏障时,主线程将被唤醒         } catch (InterruptedException e) {             e.printStackTrace();         }     } }  在这个示例中,我们创建了一个名为CyclicBarrierExample的类。main()方法中,我们创建了一个CyclicBarrier实例,并为3个线程分别分配了任务。然后,我们启动这3个线程。每个线程在完成任务后调用CyclicBarrier的await()方法,当所有线程都到达屏障时,主线程将被唤醒。  SemaphoreSemaphore是Java并发包(java.util.concurrent)中的一种同步工具,它允许一组线程在达到某个共享状态时进行互斥访问。Semaphore有两个重要类型:    1. Semaphore:Semaphore是一个计数信号量,用于控制同时访问的线程数量。创建一个Semaphore实例时,可以指定初始值和最大值。当一个线程尝试获取信号量时,如果计数小于最大值,则计数加1;否则,线程将等待直到计数减少到可用值。    2. CountDownLatch:CountDownLatch也是一个计数信号量,但它允许一个或多个线程在到达某个共享状态后继续执行。创建一个CountDownLatch实例时,可以指定初始值。当一个或多个线程调用countDown()方法时,计数减1。当计数变为0时,所有等待的线程都将被唤醒。  下面是Semaphore的示例代码:  import java.util.concurrent.Semaphore;  public class SemaphoreExample {      public static void main(String[] args) throws InterruptedException {         int initialValue = 5; // 初始化Semaphore,允许5个线程同时访问         int maxValue = 10; // 最大允许访问的线程数为10         Semaphore semaphore = new Semaphore(initialValue, maxValue); // 创建一个Semaphore实例,初始值为5,最大值为10          Thread thread1 = new Thread(new Task(semaphore));         Thread thread2 = new Thread(new Task(semaphore));         Thread thread3 = new Thread(new Task(semaphore));         Thread thread4 = new Thread(new Task(semaphore));          thread1.start();         thread2.start();         thread3.start();         thread4.start();     } }  class Task implements Runnable {      private final Semaphore semaphore;      public Task(Semaphore semaphore) {         this.semaphore = semaphore;     }      @Override     public void run() {         try {             semaphore.acquire(); // 尝试获取信号量,如果可用则计数加1,否则等待直到可用             System.out.println("Thread " + Thread.currentThread().getName() + " is running");             Thread.sleep(1000); // 模拟任务执行时间             semaphore.release(); // 释放信号量,计数减1             System.out.println("Thread " + Thread.currentThread().getName() + " completed");         } catch (InterruptedException e) {             e.printStackTrace();         }     } } 
  • [技术干货] linux下打包压缩和解压缩文件夹命令
    在linux下经常会遇到需要对某些文件或文件夹进行打包压缩、解压缩的需求,那么在linux下如何将文件和文件夹打包,怎样在linux下压缩某个文件夹命令呢?我们知道,在linux中是先打包再压缩的方式,其中常用压缩格式有:.zip ,.gz ,.bz2,.tar.gz ,.tar.bz2。而本文主要讲解tar命令。tar命令格式tar [参数] [打包文件名] [原文件]打包命令tar -cvf 打包文件名 原文件选项:-c:打包-v:显示过程-f:指定打包后的文件名例如:tar -cvf cai2022.tar cai2022 ,即为将cai2022文件夹打包成才022.tar解打包命令tar -xvf 打包文件名选项:-x:解打包例如:tar -xvf cai2022.tar,即为将cai2022.tar解压到当前目录.tar.gz格式压缩命令格式:tar -zcvf 压缩包名.tar.gz 原文件选项:-z:压缩为.tar.gz格式例如:tar -zcvf cai2022.tar.gz cai2022 //tar.gz格式是先打包为.tar格式,再压缩为.gz格式如果是分开打包和压缩:tar -cvf cai2022.tar cai2022 //先打包成.tarbzip2 cai2022.tar //再对.tar文件进行压缩成cai2022.tar.bz2解压缩命令格式:tar -zxvf 压缩包名.tar.gz选项:-x:解压缩.tar.gz格式例如:tar -zxvf cai2022.tar.gz如果是分开解压:bzip -d cai2022.tar.bz2 //先解压成tartar -xvf cai2022.tar //再解压tar.tar.bz2格式压缩压缩命令格式:tar -jcvf 压缩包名.tar.bz2 原文件选项:-z:压缩为.tar.bz2格式例如:tar -jcvf cai2022.tar.bz2 cai2022解压命令格式:tar -jxvf 压缩包名.tar.bz2选项:-x:解压缩.tar.bz2格式例如:tar -jxvf cai2022.tar.bz2补充说明如果需要指定解压缩路径,使用-C (大写C)例如:tar -jxvf cai2022.tar.bz2 -C /tmp/压缩多个文件,文件名用空格隔开例如:tar -zcvf test.tar.gz test test.php如果需要压缩到指定路径,在压缩包前加绝对路径例如:tar -zcvf /tmp/test.tar.gz test如果只查看压缩包内容而不解压,那使用选项-t例如:tar -ztvf test.tar.gz部分关键字说明z:gz格式j:bz2格式c: 压缩x: 解压缩t: 查看原文链接:https://baijiahao.baidu.com/s?id=1740784939692447868&wfr=spider&for=pc
  • [技术干货] No transaction aspect-managed TransactionStatus in scope
    出现No transaction aspect-managed TransactionStatus in scope报错排查几点: 1.service方法是否添加注解 @Transactional(rollbackFor = RuntimeException.class) 2.方法内部是否捕获异常了,并未向外抛出 a.捕获了异常可以再catch中抛出,上层处理 b.catch中增加如下,可以不向外抛出并且触发事务  TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 3.前两项确认无问题后,排查是否发生事务失效问题 样例:controller如下 service方法如下 添加事务的方法如下 上面代码中,controller调用了service的parse方法后,内部this.getServerInfo自调用了内部方法,导致事务失效从而报错。 常见几种事务失效场景: @Transactional 加于private方法, 无效 @Transactional 加于未加入接口的public方法, 再通过普通接口方法调用, 无效 @Transactional 加于接口方法, 无论下面调用的是private或public方法, 都有效 **@Transactional 加于接口方法后, 被本类普通接口方法直接调用, 无效** @Transactional 加于接口方法后, 被本类普通接口方法通过接口调用, 有效 @Transactional 加于接口方法后, 被它类的接口方法调用, 有效 @Transactional 加于接口方法后, 被它类的私有方法调用后, 有效 ———————————————— 原文链接:https://blog.csdn.net/w1028556865/article/details/125085130 
  • [技术干货] 判断String数字字符串是否为(正负)小数、整数,并转换
    在判断一个字符串数字之前,首先要分析这个字符串数字可能出现的情况  1、首位可能有符号,或者没有,^[-\\+]? 2、第二位必须是0-9的数字,[0-9] 3、第三位或者后几位可能有小数点“.”,或者没有,\\.? 4、有小数点的话,后面需要有1-n位0-9之间的数字,[0-9]+$  那么根据以上几点,最好的方式就是用正则表达式 代码如下:          String value = "-3.12";                  Boolean strResult = value.matches("^[-\\+]?([0-9]+\\.?)?[0-9]+$");         if (strResult == true ) {             System.out.println("Is Number!");             Double num = Double.parseDouble(value);             System.out.println(num);         } else {             System.out.println("Is not Number!");         } ———————————————— 原文链接:https://blog.csdn.net/su1573/article/details/86582220 
  • [技术干货] 详解BigDecimal及其加减乘除运算
     一、BigDecimal概述        浮点数值不适用于无法接受舍入误差的计算当中,比如金融计算。         例如,System.out.println(2.0-1.1)打印的结果为0.8999999999999999,而不是人们想象当中的0.9,这是为什么呢?因为System.out.println()中的数字默认是double类型的,而浮点数值采用二进制系统表示,而在二进制系统中无法精确地表示小数0.1,因此产生了这种舍入误差。         就像在十进制当中,无法精确地表示分数1/3一样。         既然浮点数都不能精确的表示出来,那么通过浮点数进行的加减乘除运算自然都不是精确的值。         如果在数值计算中需要精确的结果,不允许有这种舍入误差,那么就需要使用BigDecima类。         BigDecima是java.math包中的一个类,这个类可以处理任意长度数字序列的数值,实现了任意精度的浮点数运算。类似BigDecima,还有一个Biglnteger,实现了任意精度的整数运算。           BigDecimal所创建的是对象,故我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。  二、构造函数详解 1、BigDecimal(int val)        将 int转换成 BigDecimal对象。例如:         BigDecimal a = new BigDecimal(8);         这是通过构造函数的方式,将一个整型值转换成BigDecimal 对象,还可以通过静态的valueOf方法将普通的数值转换成BigDecimal。例如:         BigDecimal b = BigDecimal.valueOf(100);将long型数值转换成(小数位数为零的)BigDecimal。         BigDecimal c = BigDecimal.valueOf(3.14);将double型数值转换成BigDecimal。  2、BigDecimal(int val, MathContext mc)        将 int转换成 BigDecimal ,根据上下文设置进行舍入。         这里需要先讲述一下MathContext。       MathContext        MathContext是一个不可变对象,用于封装上下文设置,这些设置描述数字运算符的某些规则。它有三个构造函数:  (1)MathContext(int setPrecision)         构造具有指定精度的MathContext对象,默认的是HALF_UP舍入模式(关于舍入模式,本文后面会进行详细讲解)。  (2)MathContext(int setPrecision, RoundingMode setRoundingMode)         使用指定的精度和舍入模式构造新的MathContext对象。  (3)MathContext(String val)         使用字符串构造一个MathContext对象。         使用示例如下,  MathContext mathContext = new MathContext(4); BigDecimal d = new BigDecimal(12345, mathContext); System.out.println(d);        打印的结果为:1.235E+4         分析上述代码。第一行代码创建了一个MathContext 对象,指定的精度为4,也就是4位有效数字。第二行代码利用整型的“12345”和mathContext创建了一个BigDecimal对象,将12345保留4位有效数字转换成BigDecimal。12345保留四位有效数字的结果也就是1.235E+4(1.235乘于10的四次方)。  3、BigDecimal(long val)        将 long转换成 BigDecimal 。  4、BigDecimal(long val, MathContext mc)        将 long转换为 BigDecimal ,根据上下文设置进行舍入。  5、BigDecimal(BigInteger val)        将 BigInteger转换成 BigDecimal 。  6、BigDecimal(BigInteger unscaledVal, int scale)        将BigInteger的 BigInteger值和 int等级转换为 BigDecimal 。  7、BigDecimal(BigInteger unscaledVal, int scale, MathContext mc)        将 BigInteger未缩放值,根据scale和mc ,转换为 BigDecimal 。  8、BigDecimal(BigInteger val, MathContext mc)        根据上下文设置将 BigInteger转换为 BigDecimal,根据上下文设置进行舍入。  9、BigDecimal(double val)        将 double转换为 BigDecimal ,这是 double的二进制浮点值的精确十进制表示。  10、BigDecimal(double val, MathContext mc)        将 double转换为 BigDecimal ,根据上下文设置进行舍入。  11、BigDecimal(char[] in)        将字符数组转换成 BigDecimal 。  12、BigDecimal(char[] in, int offset, int len)        将字符数组转换成 BigDecimal,同时允许一个子阵列被指定。  13、BigDecimal(char[] in, int offset, int len, MathContext mc)        将字符数组转换成 BigDecimal,同时允许指定一个子阵列和用根据上下文设置进行舍入。  14、BigDecimal(char[] in, MathContext mc)       将字符数组转换成 BigDecimal ,根据上下文设置进行舍入。  15、BigDecimal(String val)        常用!!!将字符串表示的数字转换为 BigDecimal 。  16、BigDecimal(String val, MathContext mc)        常用!!!将字符串表示的数字转换为 BigDecimal ,根据上下文设置进行舍入。         可以看到,BigDecimal的构造函数很多,根据自己的需要,大家选择合适的构造函数创建对应的BigDecimal对象就行了。但是有一点需要注意,就是以数值型参数创建BigDecimal对象的时候,会产生精度问题。        例如,  System.out.println(new BigDecimal(0.1)); System.out.println(new BigDecimal("0.1"));        打印结果为:     0.1000000000000000055511151231257827021181583404541015625 0.1         可以看到,通过double类型的0.1创建BigDecimal对象的时候,实际打印的值并不是精确的0.1,通过String类型创建的BigDecimal对象,实际打印的值是0.1。这是为什么呢?         因为参数类型为double的构造方法的结果有一定的不可预知性。不熟悉BigDecimal的人可能会认为在Java中通过newBigDecimal(0.1)所创建的BigDecimal正好等于 0.1,但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。因为0.1无法用二进制精确地表示出来,本来开头亦对此进行了解释。这样,传入到构造方法的值并不是我们看到的0.1,实际上传的是0.1000000000000000055511151231257827021181583404541015625,因此产生了上述的打印结果。         String 构造方法是完全可预知的:通过 newBigDecimal(“0.1”) 将创建一个 BigDecimal对象,它正好等于预期的 0.1。因此, 通常建议优先使用String构造方法。  三、BigDecimal的加、减、乘、除、绝对值 1、加法        加法对应的方法有两个:  (1)public BigDecimal add(BigDecimal augend);         方法返回的是一个BigDecimal对象,值为当前对象的值加上被加数对象augend的值(this+augend)。保留的小数位数是max(this.scale(), augend.scale()).  (2) public BigDecimal add(BigDecimal augend,MathContext mc);         方法返回的是一个BigDecimal对象,值为当前对象的值加上被加数对象augend的值(this+augend),并根据上下文设置进行舍入。(关于上下文MathContext,前文已解释过)         加法示例如下,      @Test     public void testAdd() {         //用double类型初始化BigDecimal对象         BigDecimal numA = new BigDecimal(0.05);         BigDecimal numB = new BigDecimal(0.06);         System.out.println("numA + numB = " + numA.add(numB));         //用double类型和int类型初始化BigDecimal对象。(作加法运算时得到的只是一个近似值)         BigDecimal numC = new BigDecimal(3.05);         BigDecimal numD = new BigDecimal(100);         System.out.println("numC + numD = " + numC.add(numD));         //用字符串类型初始化BigDecimal对象。(作加法运算时得到的是精确值)         BigDecimal strA = new BigDecimal("3.05");         BigDecimal strB = new BigDecimal("100");         System.out.println("strA + strB = " + strA.add(strB));     }       打印的结果如下:  numA + numB = 0.11000000000000000055511151231257827021181583404541015625 numC + numD = 103.04999999999999982236431605997495353221893310546875 strA + strB = 103.05         可以看到,使用double类型初始化BigDecimal 对象,进行加法运算时就出现了精度问题。正如前文所说,并不是所有的浮点数都能够在二进制系统中被精确的表示,自然而然的在进行加减乘除运算时就会出错。  2、减法        对应的方法有两个: (1)public BigDecimal subtract(BigDecimal subtrahend);         方法返回的是一个BigDecimal对象,值为当前对象的值减去被减数对象subtrahend的值(this-subtrahend)。保留的小数位数是max(this.scale(), subtrahend.scale()).。     (2)public BigDecimal subtract(BigDecimal subtrahend,MathContext mc);         方法返回的是一个BigDecimal对象,值为当前对象的值减去被减数对象subtrahend的值(this-subtrahend),并根据上下文设置进行舍入。         减法示例如下,      @Test     public void testSubtract() {         //用double类型初始化BigDecimal对象         BigDecimal numA = new BigDecimal(0.05);         BigDecimal numB = new BigDecimal(0.06);         System.out.println("numA + numB = " + numA.subtract(numB));         //用double类型和int类型初始化BigDecimal对象。(作减法运算时得到的只是一个近似值)         BigDecimal numC = new BigDecimal(100);         BigDecimal numD = new BigDecimal(0.05);         System.out.println("numC + numD = " + numC.subtract(numD));         //用字符串类型初始化BigDecimal对象。(作减法运算时得到的是精确值)         BigDecimal strA = new BigDecimal("100");         BigDecimal strB = new BigDecimal("0.05");         System.out.println("strA + strB = " + strA.subtract(strB));     }        打印结果如下:  numA + numB = -0.00999999999999999500399638918679556809365749359130859375 numC + numD = 99.94999999999999999722444243843710864894092082977294921875 strA + strB = 99.95  3、乘法        对应的方法有:  (1)public BigDecimal multiply(BigDecimal multiplicand);         方法返回的是一个BigDecimal对象,值为当前对象的值乘于被乘数对象multiplicand的值(this*multiplicand)。保留的小数位数是(this.scale() + multiplicand.scale()).。     (2)public BigDecimal multiply(BigDecimal multiplicand,MathContext mc);        方法返回的是一个BigDecimal对象,值为当前对象的值乘于被乘数对象subtrahend的值(this*multiplicand),并根据上下文设置进行舍入。        乘法示例如下,      @Test     public void testMultiply() {         //用double类型初始化BigDecimal对象         BigDecimal numA = new BigDecimal(0.05);         BigDecimal numB = new BigDecimal(0.06);         System.out.println("numA + numB = " + numA.multiply(numB));         //用double类型和int类型初始化BigDecimal对象。(作乘法运算时得到的只是一个近似值)         BigDecimal numC = new BigDecimal(100);         BigDecimal numD = new BigDecimal(0.05);         System.out.println("numC + numD = " + numC.multiply(numD));         //用字符串类型初始化BigDecimal对象。(作乘法运算时得到的是精确值)         BigDecimal strA = new BigDecimal("100");         BigDecimal strB = new BigDecimal("0.05");         System.out.println("strA + strB = " + strA.multiply(strB)); }       打印结果如下, numA + numB = 0.00300000000000000005551115123125782085820576136538628584587058372823258067807472571075777523219585418701171875 numC + numD = 5.00000000000000027755575615628913510590791702270507812500 strA + strB = 5.00 4、除法        对应的方法主要有: (1) public BigDecimal divide(BigDecimal divisor);        返回一个BigDecimal,其值为(this/divisor),首选小数位数为(this.scale()-divisor.scale());如果无法表示精确的商(因为它具有非终止的十进制扩展),则会引发算术异常。 (2) public BigDecimal divide(BigDecimal divisor,MathContext mc);        返回值为(this/divisor)的BigDecimal,并根据上下文设置进行舍入。  (3) public BigDecimal divide(BigDecimal divisor,int scale,int roundingMode);        返回一个BigDecimal,其值为(this/divisor),其小数位数与指定的相同。如果必须执行舍入才能生成具有指定比例的结果,则应该用指定的舍入模式。 (4) public BigDecimal divide(BigDecimal divisor,int scale,RoundingMode roundingMode);        返回一个BigDecimal,其值为(this/divisor),其小数位数与指定的相同(由第二个参数scale指定)。如果必须执行舍入才能生成具有指定比例的结果,则应该用指定的舍入模式(由第三个参数roundingMode指定)。        (3)(4)两个方法其实是一样的,区别只在于第三个参数的指定方式。第一个方法是int roundingMode,即传入的是一个整型数字,而第二个方法是RoundingMode roundingMode,即传入的是一个RoundingMode对象。         这里需要对RoundingMode作一下介绍。      RoundingMode        RoundingMode是一个枚举类,内部有8个枚举常量,分别是:        UP:远离0的舍入模式,在丢弃非零部分之前始终增加数字(始终对非零舍弃部分前面的数字加1)。放到一维坐标轴上就很容易理解,就是以0为分隔点,0右侧部分一直向右舍入,0左侧部分一直向左侧舍入。例如0.333保留两位小数,采用UP舍入模式的结果为0.34,-0.333保留两位小数,采用UP舍入模式的结果为-0.34。        DOWN:和UP相反,是接近零的舍入模式。理解了UP舍入模式,就很容易理解DOWN舍入模式。例如0.333保留两位小数,采用DOWN舍入模式的结果为0.33,-0.333保留两位小数,采用DOWN舍入模式的结果为-0.33。可以发现,在采用DOWN模式进行舍入的时候,直接把需要舍弃的位数丢掉就行了。        CEILING:CEILING英文是天花板的意思,可以理解为向”大“舍入。如果 BigDecimal 为正,则舍入行为与 UP 相同,如果为负,则舍入行为与 DOWN 相同。例如0.333保留两位小数,采用CEILING舍入模式的结果为0.34(0.34 >0.333),-0.333保留两位小数,采用CEILING舍入模式的结果为-0.33(-0.33>0.333 )。        FLOOR:与CEILING相反,FLOOR有地板的意思,可以理解为向”小“舍入。如果 BigDecimal 为正,则舍入行为与 DOWN 相同,如果为负,则舍入行为与 UP 相同。例如0.333保留两位小数,采用FLOOR舍入模式的结果为0.33,-0.333保留两位小数,采用FLOOR舍入模式的结果为-0.34。        HALF_UP:向”最接近的“数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。如果舍弃部分 >= 0.5,则舍入行为与 UP 相同,否则舍入行为与 DOWN 相同。其实就是四舍五入。        HALF_DOWN:向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。如果舍弃部分 > 0.5,则舍入行为与UP 相同,否则舍入行为与 DOWN 相同。与四舍五入的思路是一样的,只不过这里是”五舍六入“。如果扣字面意思的话,也很好理解,HALF_UP,half是一半的意思,也就是5,UP是向上的意思,就可以理解为5向上入,即四舍五入。同理,HALF_DOWN,5向下舍,即五舍六入。        HALF_EVEN:向“最接近的”数字舍入。如果舍弃部分左边的数字为奇数,则舍入行为与 UP 相同,如果为偶数,则舍入行为与 DOWN 相同。如0.135,保留两位小数,舍弃5,因为3是奇数,所以与UP相同,结果为0.14;0.125,保留两位小数,舍弃5,因为2是偶数,所以与DOWN相同,结果为0.12.        UNNECESSARY:以断言请求的操作具有精确的结果,因此不需要舍入。如果有舍入,会报java.lang.ArithmeticException异常。        关于这几个舍入模式的结果,亦可参照下面的表进行快速学习。  保留整数,不同舍入模式下的计算结果 原数    UP    DOWN    CEILING    FLOOR    HALF_UP    HALF_DOWN    HALF_EVEN    UNNECESSARY 5.5    6    5    6    5    6    5    6    throw ArithmeticException 2.5    3    2    3    2    3    2    2    throw ArithmeticException 1.6    2    1    2    1    2    2    2    throw ArithmeticException 1.1    2    1    2    1    1    1    1    throw ArithmeticException 1.0    1    1    1    1    1    1    1    1 -1.0    -1    -1    -1    -1    -1    -1    -1    -1 -1.1    -2    -1    -1    -2    -1    -1    -1    throw ArithmeticException -1.6    -2    -1    -1    -2    -2    -2    -2    throw ArithmeticException -2.5    -3    -2    -2    -3    -3    -2    -2    throw ArithmeticException -5.5    -6    -5    -5    -6    -6    -5    -6    throw ArithmeticException                                                  代码示例如下,  @Test public void testDivide() {         BigDecimal numA = new BigDecimal("1");         BigDecimal numB = new BigDecimal("-1");         BigDecimal numC = new BigDecimal("3");         // 保留两位小数,舍入模式为UP         System.out.println("1/3保留两位小数(UP) = " + numA.divide(numC, 2, RoundingMode.UP));         System.out.println("-1/3保留两位小数(UP) = " + numB.divide(numC, 2, RoundingMode.UP));         // 保留两位小数,舍入模式为DOWN         System.out.println("1/3保留两位小数(DOWN) = " + numA.divide(numC, 2, RoundingMode.DOWN));         System.out.println("-1/3保留两位小数(DOWN) = " + numB.divide(numC, 2, RoundingMode.DOWN));         // 保留两位小数,舍入模式为CEILING         System.out.println("1/3保留两位小数(CEILING) = " + numA.divide(numC, 2, RoundingMode.CEILING));         System.out.println("-1/3保留两位小数(CEILING) = " + numB.divide(numC, 2, RoundingMode.CEILING));         // 保留两位小数,舍入模式为FLOOR         System.out.println("1/3保留两位小数(FLOOR) = " + numA.divide(numC, 2, RoundingMode.FLOOR));         System.out.println("-1/3保留两位小数(FLOOR) = " + numB.divide(numC, 2, RoundingMode.FLOOR));           BigDecimal numD = new BigDecimal("1");         BigDecimal numE = new BigDecimal("-1");         BigDecimal numF = new BigDecimal("8");         // 保留两位小数,舍入模式为HALF_UP         System.out.println("1/8(=0.125)保留两位小数(HALF_UP) = " + numD.divide(numF, 2, RoundingMode.HALF_UP));         System.out.println("-1/8(=0.125)保留两位小数(HALF_UP) = " + numE.divide(numF, 2, RoundingMode.HALF_UP));         // 保留两位小数,舍入模式为HALF_DOWN         System.out.println("1/8(=0.125)保留两位小数(HALF_DOWN) = " + numD.divide(numF, 2, RoundingMode.HALF_DOWN));         System.out.println("-1/8(=0.125)保留两位小数(HALF_DOWN) = " + numE.divide(numF, 2, RoundingMode.HALF_DOWN));           // 保留两位小数,舍入模式为HALF_EVEN         System.out.println("0.54/4(=0.135)保留两位小数(HALF_EVEN) = " + new BigDecimal("0.54").divide(new BigDecimal("4"), 2, RoundingMode.HALF_EVEN));         System.out.println("1/8(=0.125)保留两位小数(HALF_EVEN) = " + numE.divide(numF, 2, RoundingMode.HALF_EVEN));           //UNNECESSARY,会报异常         System.out.println("1/8(=0.125) = " + numE.divide(numF,  RoundingMode.UNNECESSARY)); } 打印结果:  1/3保留两位小数(UP) = 0.34 -1/3保留两位小数(UP) = -0.34 1/3保留两位小数(DOWN) = 0.33 -1/3保留两位小数(DOWN) = -0.33 1/3保留两位小数(CEILING) = 0.34 -1/3保留两位小数(CEILING) = -0.33 1/3保留两位小数(FLOOR) = 0.33 -1/3保留两位小数(FLOOR) = -0.34 1/8(=0.125)保留两位小数(HALF_UP) = 0.13 -1/8(=0.125)保留两位小数(HALF_UP) = -0.13 1/8(=0.125)保留两位小数(HALF_DOWN) = 0.12 -1/8(=0.125)保留两位小数(HALF_DOWN) = -0.12 0.54/4(=0.135)保留两位小数(HALF_EVEN) = 0.14 1/8(=0.125)保留两位小数(HALF_EVEN) = -0.12  java.lang.ArithmeticException: Rounding necessary  5、绝对值    public BigDecimal abs();        返回一个BigDecimal,其值为该BigDecimal的绝对值,其小数位数为this.scale()。     public BigDecimal abs(MathContext mc);       返回一个BigDecimal,其值是此BigDecimal的绝对值,并根据上下文设置进行舍入。        代码示例,      @Test     public void testAbs() {         BigDecimal a = new BigDecimal("1.234");         BigDecimal b = new BigDecimal("-1.234");         System.out.println("1.234的绝对值:" + a.abs());         System.out.println("-1.234的绝对值:" + b.abs());         System.out.println("-1.234的绝对值,保留两位有效数字:" + b.abs(new MathContext(2)));     }        打印结果为:  1.234的绝对值:1.234 -1.234的绝对值:1.234 -1.234的绝对值,保留两位有效数字:1.2 ———————————————— 原文链接:https://blog.csdn.net/AttleeTao/article/details/103950423 
  • [技术干货] BigDecimal 除法
    BigDecimal 除法 除法 常用方法 divide(BigDecimal divisor, int scale, int roundingMode)  参数    释义 divisor    被除数 scale    保留小数位 roundingMode    舍入模式 示例 BigDecimal b1 = new BigDecimal("3"); BigDecimal b2 = new BigDecimal("7"); //计算b1除以b2的值并四舍五入保留两位小数 b1 = b1.divide(b2, 2 ,BigDecimal.ROUND_HALF_UP); System.out.println("结果:"+b1); 结果:  结果:0.43 舍入模式 模式    释义 ROUND_UP    只要舍去的值不为0,则进1。如1.010保留一位小数为1.1,保留两位小数为1.01。 ROUND_DOWN    无论舍去的值是多少,直接舍去(截断)。 ROUND_CEILING    向正无穷方向舍入,若是正数则表现为’ROUND_UP’,若为负数则表现为’ROUND_DOWN’。 ROUND_FLOOR    向负无穷方向舍入,若是正数则表现为’ROUND_DOWN’,若为负数则表现为ROUND_UP’’。 ROUND_HALF_UP    四舍五入。 ROUND_HALF_DOWN    五舍六入。 ROUND_HALF_EVEN    若舍去位数左边值为偶数,则五舍六入。若舍去位数左边值为奇数,则四舍五入。 ROUND_UNNECESSARY    断言得数为精确的结果,若不是则抛出ArithmeticException。 ROUND_UP 示例:  BigDecimal b1 = new BigDecimal("1.11"); BigDecimal b2 = new BigDecimal("1.10"); BigDecimal one = new BigDecimal("1");  b1 = b1.divide(one, 1 ,BigDecimal.ROUND_UP); b2 = b2.divide(one, 1, BigDecimal.ROUND_UP);  System.out.println("b1结果:"+b1); System.out.println("b2结果:"+b2); 结果:  b1结果:1.2 b2结果:1.1 ROUND_DOWN 示例:  BigDecimal b1 = new BigDecimal("1.11"); BigDecimal b2 = new BigDecimal("1.10"); BigDecimal one = new BigDecimal("1");  b1 = b1.divide(one, 1 ,BigDecimal.ROUND_DOWN); b2 = b2.divide(one, 1, BigDecimal.ROUND_DOWN);  System.out.println("b1结果:"+b1); System.out.println("b2结果:"+b2); 结果:  b1结果:1.1 b2结果:1.1 ROUND_CEILING 示例:  BigDecimal b1 = new BigDecimal("-1.11"); BigDecimal b2 = new BigDecimal("1.11"); BigDecimal one = new BigDecimal("1");  b1 = b1.divide(one, 1 ,BigDecimal.ROUND_CEILING); b2 = b2.divide(one, 1, BigDecimal.ROUND_CEILING);  System.out.println("b1结果:"+b1); System.out.println("b2结果:"+b2); 结果:  b1结果:-1.1 b2结果:1.2 ROUND_FLOOR 示例:  BigDecimal b1 = new BigDecimal("-1.11"); BigDecimal b2 = new BigDecimal("1.11"); BigDecimal one = new BigDecimal("1");  b1 = b1.divide(one, 1 ,BigDecimal.ROUND_FLOOR); b2 = b2.divide(one, 1, BigDecimal.ROUND_FLOOR);  System.out.println("b1结果:"+b1); System.out.println("b2结果:"+b2); 结果:  b1结果:-1.2 b2结果:1.1 ROUND_HALF_UP 示例:  BigDecimal b1 = new BigDecimal("1.14"); BigDecimal b2 = new BigDecimal("1.15"); BigDecimal one = new BigDecimal("1");  b1 = b1.divide(one, 1 ,BigDecimal.ROUND_HALF_UP); b2 = b2.divide(one, 1, BigDecimal.ROUND_HALF_UP);  System.out.println("b1结果:"+b1); System.out.println("b2结果:"+b2); 结果:  b1结果:1.1 b2结果:1.2 ROUND_HALF_DOWN 示例: BigDecimal b1 = new BigDecimal("1.15"); BigDecimal b2 = new BigDecimal("1.16"); BigDecimal one = new BigDecimal("1"); b1 = b1.divide(one, 1 ,BigDecimal.ROUND_HALF_DOWN); b2 = b2.divide(one, 1, BigDecimal.ROUND_HALF_DOWN); System.out.println("b1结果:"+b1); System.out.println("b2结果:"+b2); 结果: b1结果:1.1 b2结果:1.2 ROUND_HALF_EVEN 示例: BigDecimal b1 = new BigDecimal("1.15"); BigDecimal b2 = new BigDecimal("1.25"); BigDecimal one = new BigDecimal("1"); b1 = b1.divide(one, 1 ,BigDecimal.ROUND_HALF_EVEN); b2 = b2.divide(one, 1, BigDecimal.ROUND_HALF_EVEN); System.out.println("b1结果:"+b1); System.out.println("b2结果:"+b2); 结果: b1结果:1.2 b2结果:1.2 ROUND_UNNECESSARY 结果精度确定: BigDecimal b1 = new BigDecimal("10"); BigDecimal one = new BigDecimal("2"); b1 = b1.divide(one, 1 ,BigDecimal.ROUND_UNNECESSARY); System.out.println("b1结果:"+b1); 结果: b1结果:5.0 结果精度不确定: BigDecimal b1 = new BigDecimal("3"); BigDecimal one = new BigDecimal("7"); b1 = b1.divide(one, 1 ,BigDecimal.ROUND_UNNECESSARY); System.out.println("b1结果:"+b1); 结果: Exception in thread "main" java.lang.ArithmeticException: Rounding necessary at java.math.BigDecimal.commonNeedIncrement(BigDecimal.java:4148) at java.math.BigDecimal.needIncrement(BigDecimal.java:4204) at java.math.BigDecimal.divideAndRound(BigDecimal.java:4112) at java.math.BigDecimal.divide(BigDecimal.java:5183) at java.math.BigDecimal.divide(BigDecimal.java:1561) at test.test.main(test.java:10) ———————————————— 原文链接:https://blog.csdn.net/weixin_42889176/article/details/108188226 
  • [技术干货] LocalDateTime获取 年月日时分秒和判断日期大小
    环境:java version "13.0.1"。创建一个DateUtils类,提供三个常用方法:String 转换 LocalDateTime的方法。获取LocalDateTime获取 年月日时分秒。两个时间的间隔毫秒数,常用于判断日期大小。import org.springframework.util.StringUtils; import java.text.DateFormat; import java.time.DayOfWeek; import java.time.Duration; import java.time.LocalDateTime; import java.time.Month; import java.time.format.DateTimeFormatter; import java.util.Calendar; import java.util.Date; public class DateUtils { private static DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS"); public static void getTimeByDate() { Date date = new Date(); DateFormat df1 = DateFormat.getDateInstance();//日期格式,精确到日 System.out.println(df1.format(date)); DateFormat df2 = DateFormat.getDateTimeInstance();//可以精确到时分秒 System.out.println(df2.format(date)); DateFormat df3 = DateFormat.getTimeInstance();//只显示出时分秒 System.out.println(df3.format(date)); DateFormat df4 = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL); //显示日期,周,上下午,时间(精确到秒) System.out.println(df4.format(date)); DateFormat df5 = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG); //显示日期,上下午,时间(精确到秒) System.out.println(df5.format(date)); DateFormat df6 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); //显示日期,上下午,时间(精确到分) System.out.println(df6.format(date)); DateFormat df7 = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); //显示日期,时间(精确到分) System.out.println(df7.format(date)); } public static void getTimeByCalendar() { Calendar cal = Calendar.getInstance(); int year = cal.get(Calendar.YEAR);//获取年份 int month = cal.get(Calendar.MONTH);//获取月份 int day = cal.get(Calendar.DATE);//获取日 int hour = cal.get(Calendar.HOUR);//小时 int minute = cal.get(Calendar.MINUTE);//分 int second = cal.get(Calendar.SECOND);//秒 int WeekOfYear = cal.get(Calendar.DAY_OF_WEEK);//一周的第几天 System.out.println("现在的时间是:公元" + year + "年" + month + "月" + day + "日," + hour + "时" + minute + "分" + second + "秒, 一周的第几天:" + WeekOfYear); } /** * 获取指定时间的年月日等 * @param localDateTime 指定时间 */ public static void getTimeByGivenLocalDateTime(LocalDateTime localDateTime) { if (null == localDateTime) { localDateTime = LocalDateTime.now(); } int dayOfYear = localDateTime.getDayOfYear(); int dayOfMonth = localDateTime.getDayOfMonth(); DayOfWeek dayOfWeek = localDateTime.getDayOfWeek(); System.out.println("今天是" + localDateTime + "\n" + "本年当中第" + dayOfYear + "天" + "\n" + "本月当中第" + dayOfMonth + "天" + "\n" + "本周中星期" + dayOfWeek.getValue() + "-即" + dayOfWeek + "\n"); //获取指定时间的年月日时分秒 int year = localDateTime.getYear(); Month month = localDateTime.getMonth(); int day = localDateTime.getDayOfMonth(); int hour = localDateTime.getHour(); int minute = localDateTime.getMinute(); int second = localDateTime.getSecond(); System.out.println("今天是" + localDateTime + "\n" + "年 : " + year + "\n" + "月 : " + month.getValue() + "-即 " + month + "\n" + "日 : " + day + "\n" + "时 : " + hour + "\n" + "分 : " + minute + "\n" + "秒 : " + second + "\n" ); } /** * String 转换 LocalDateTime * @param dateStr * @return */ public static LocalDateTime string2Time(String dateStr) { if (StringUtils.isEmpty(dateStr)) { return null; } LocalDateTime time = LocalDateTime.parse(dateStr, fmt); System.out.println("time:" + time); return time; } /** * 求时间间隔,返回值大于零说明结束时间晚于开始时间 * @param beginTime 开始时间 * @param endTime 结束时间 * @return 毫秒,等于endTime 减去 beginTime后的毫秒数 */ public static Long between(LocalDateTime beginTime, LocalDateTime endTime) { Duration duration = Duration.between(beginTime, endTime); return duration.toMillis(); } public static void main(String[] args) { getTimeByDate(); System.out.println("********getTimeByCalendar********************"); getTimeByCalendar(); System.out.println("********getTimeByGivenLocalDateTime****************"); String str = "2021-10-09 15:32:06:777"; LocalDateTime ldt = string2Time(str); getTimeByGivenLocalDateTime(ldt); System.out.println("********between****************"); str = "2021-10-09 17:32:06:777"; LocalDateTime endTime = string2Time(str); System.out.println(between(ldt, endTime)); } } 测试结果:2021年10月10日 2021年10月10日 下午12:06:02 下午12:06:02 2021年10月10日星期日 中国标准时间 下午12:06:02 2021年10月10日 CST 下午12:06:02 2021/10/10 下午12:06 2021年10月10日 下午12:06:02 ********getTimeByCalendar******************** 现在的时间是:公元2021年9月10日,0时6分2秒, 一周的第几天:1 ********getTimeByGivenLocalDateTime**************** time:2021-10-09T15:32:06.777 今天是2021-10-09T15:32:06.777 本年当中第282天 本月当中第9天 本周中星期6-即SATURDAY 今天是2021-10-09T15:32:06.777 年 : 2021 月 : 10-即 OCTOBER 日 : 9 时 : 15 分 : 32 秒 : 6 ********between**************** time:2021-10-09T17:32:06.777 7200000 Process finished with exit code 0原文链接:https://www.cnblogs.com/east7/p/15389080.html
  • [技术干货] @PathVariable注解的用法和作用
    @PathVariable是spring3.0的一个新功能:接收请求路径中占位符的值 语法:  @PathVariable("xxx") 通过 @PathVariable 可以将URL中占位符参数{xxx}绑定到处理器类的方法形参中@PathVariable(“xxx“)  @RequestMapping(value=”user/{id}/{name}”) 请求路径:http://localhost:8080/hello/show5/1/james 测试环境: 环境:jdk1.8 Tomcat8.5  idea2018  manven父工程子模块 步骤: 1、创建web工程、引入依赖 2、配置SpringMvc入口文件 --DispatcherServlet--为总调度、web.xml里配置 3、创建Springmvc.xml文件--理解为:适配器(这里不需要自已指定适配、springmvc会自动指定)--视图解析器 4、创建 业务处理器 Controller类 步骤1、2、3、参考:SpringMvc入门案例:https://blog.csdn.net/sswqzx/article/details/84171999 业务处理器HelloController.java  package com.day01springmvc.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView;   /**  * @ Author     :ShaoWei Sun.  * @ Date       :Created in 20:58 2018/11/16  */ @Controller @RequestMapping("hello") public class HelloController2 {     /**      *3、占位符映射      * 语法:@RequestMapping(value=”user/{userId}/{userName}”)      * 请求路径:http://localhost:8080/hello/show5/1/james      * @param ids      * @param names      * @return      */     @RequestMapping("show5/{id}/{name}")     public ModelAndView test5(@PathVariable("id") Long ids ,@PathVariable("name") String names){         ModelAndView mv = new ModelAndView();         mv.addObject("msg","占位符映射:id:"+ids+";name:"+names);         mv.setViewName("hello2");         return mv;     } }                                              ———————————————— 原文链接:https://blog.csdn.net/sswqzx/article/details/84194979 
  • [技术干货] Ambiguous handler methods mapped for 'xxx'的解决办法
    Ambiguous handler methods mapped for '/book/es' 一. 问题描述 我们在创建Restful风格的url的时候,可以直接将参数变量值放入到url中,然后传递到后台,后台自动识别对应的方法,非常的方便.  但是如果我们的接口方法中出现了方法重载的情况,则有可能会出现一些问题,如下:  package com.syc.boot.web;   import com.syc.boot.domain.Book; import com.syc.boot.service.BookService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Optional;   @Slf4j @RestController public class ElasticController {       @Autowired     private BookService bookService;       @RequestMapping("/book/{id}")     public Book getBookById(@PathVariable String id) {         Optional<Book> opt = bookService.findById(id);         Book book = opt.get();         log.warn(book.toString());         return book;     }       @RequestMapping("/book/{title}")     public Page<Book> getBookByTitleHighLight(@PathVariable("title") String title) {         Page<Book> books = bookService.findByTitle(title, 1, 10);         log.warn(books.toString());         return books;     }   } 此时在浏览器地址栏访问 http://localhost:8080/book/1 或 http://localhost:8080/book/es教程 时均会出现如下错误.  java.lang.IllegalStateException: Ambiguous handler methods mapped for '/book/es': {public com.syc.boot.domain.Book com.syc.boot.web.ElasticController.getBookById(java.lang.String), public org.springframework.data.domain.Page com.syc.boot.web.ElasticController.getBookByTitleHighLight(java.lang.String)}   意思是说我们的Controller中,有两个模棱两可的处理方法,这两个方法有歧义,无法分清谁是谁.因为Spring无法根据传参的类型自动匹配到可以处理的方法.  此时如果我们依然想使用Restful编程风格,就必须改变请求得url格式,保证url对应的方法不会产生歧义.  二. 解决办法 针对上面的例子,只要保证一个类中多个方法请求的接口方法不一样就可以了,可以是请求方法,请求参数,url等不同,这样就可以匹配到不同的方法.  package com.syc.boot.web;   import com.syc.boot.domain.Book; import com.syc.boot.service.BookService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Optional;   @Slf4j @RestController public class ElasticController {       @Autowired     private BookService bookService;       @RequestMapping("/book/id/{id}")     public Book getBookById(@PathVariable String id) {         Optional<Book> opt = bookService.findById(id);         Book book = opt.get();         log.warn(book.toString());         return book;     }       @RequestMapping("/book/title/{title}")     public Page<Book> getBookByTitleHighLight(@PathVariable("title") String title) {         Page<Book> books = bookService.findByTitle(title, 1, 10);         log.warn(books.toString());         return books;     }  } 此时再到浏览器地址栏通过 http://localhost:8080/user/id/1 或 http://localhost:8080/user/title/es 来请求. 就可以可以正常访问到后台的对象内容了. ———————————————— 原文链接:https://blog.csdn.net/syc000666/article/details/94978731 
  • [技术干货] Linux下Graphics2D.drawString(message, px, py)乱码问题
     今天遇到了一个乱码问题,合成的小票图片上的中文全部变成了口口口,后来在网上查了资料,发现是Graphics2D用了宋体字,而linux服务器上没有对应的字体库。 把本地的字体库上传上去就解决了。 本地字体库位置:(winXP 宋体字)C:\WINDOWS\Fonts\simsun.ttc simsun.ttc 改名为 simsun.ttf 复制到linux:/usr/java/jdk1.7.0_79/jre/lib/fonts/ 参考文档:http://ember319.iteye.com/blog/254015 以下为原文内容 问题描述: 用户使用手机登录我们系统,在订购产品时,需要从服务器端下载一张图片,显示到手机屏幕上,该图片上可能包含中英文字符,视情况而定。 结果测试下来,英文没有问题,中文打印为方块。 环境描述: 开发平台为WinXP,测试环境为Solaris10。   数据来源: 用以打印到图片的信息通过Web serice从另一系统获取。 下面说一下解决的思路, 1、是否字符编码问题 为了检查获取的字符串的编码是否正确,使用下面的方式尝试多种字符集编码的转换,但是都没有效果; Java代码   String message=“...”;//ws获取到的信息   new String(message.getBytes("utf8"),"gbk");   回过来仔细考虑了一下我们的系统,系统的jsp页面及数据库编码都是采用的utf-8编码,无论是录入、保存还是显示都没有出现中文乱码问题;尤其是系统之间多处使用ws方式同步数据,也没有出现乱码问题,于是认为ws获取到的信息同样是utf-8编码。为了验证这个想法,做了一个jsp页面,使用utf-8的方式显示获取到的信息,在不经过任何转换的前提下,正确显示中文。最终确定,不是字符集编码的问题。 2、是否打印过程发生了问题 查看了JDK API的说明,发现在使用字体的时候,我没有特别设定,使用了默认字体。写了一个简单的输出平台默认字体的类,得到的字体却是一样的信息: Java代码   Default font:java.awt.Font[family=Dialog,name=Dialog,style=plain,size=12]   1) 指定打印到图片的字体为中文 Java代码   g2d.setFont(new Font("宋体", Font.PLAIN, 12));   2) 上传WinXp 中的宋体字体文件到服务器(Solaris) 我的本地字体文件地址是“C:\WINDOWS\Fonts\simsun.ttc”,上传到服务器地址是:“/usr/jdk/instances/jdk1.5.0/jre/lib/fonts/simsun.ttf” 打印图片中文乱码问题到这里就解决了。 考虑起来,因为打印字符成为图片,需要用到像素排列,如果字体不对,的确是没有办法打印啊。 ———————————————— 原文链接:https://blog.csdn.net/itjauser/article/details/88723604 
总条数:2301 到第 页
上滑加载中