-
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
-
默认情况下,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对象。
-
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 。
-
大家好,这个月给大家带来的是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
-
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事件的机制,它们各有优缺点,适用于不同的场景。在选择使用哪种机制时,需要根据具体的应用场景来进行选择。
-
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中是先打包再压缩的方式,其中常用压缩格式有:.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报错排查几点: 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
-
在判断一个字符串数字之前,首先要分析这个字符串数字可能出现的情况 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概述 浮点数值不适用于无法接受舍入误差的计算当中,比如金融计算。 例如,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 除法 除法 常用方法 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
-
环境: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是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 '/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
-
今天遇到了一个乱码问题,合成的小票图片上的中文全部变成了口口口,后来在网上查了资料,发现是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
上滑加载中
推荐直播
-
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
华为云开发者AI素养直播课·第五期2026/09/04 周五 16:00-18:00
林华鼎-华为云AI开发者运营负责人;蒋春阳-华为云AI开发者案例开发专家
本期直播内容: AI工具体验营 · 第5-8课连讲。Agent-Team 多智能体协作完成毕业设计实践
回顾中 -
华为云开发者AI素养ClassRoom·第六期2026/09/08 周二 19:00-20:00
樊渊-2026华为软件挑战赛冠军
高手来了:看软挑高手解析二维排样问题—从工业难题到算法突破
回顾中
热门标签