使用LocalDateTime替代Date操作处理日期时间之后:任凭风浪起,稳坐钓鱼台

1.概述

在日常开发系统过程中,日期和时间的操作处理是一个常见的应用功能场景,Java提供了多种工具和库来处理日期和时间操作,其中主要分为:Java 8之前的提供java.util.Datejava.util.Calendar。Java 8引入了全新的日期时间API,提供了更好用且更强大的日期时间处理功能,主要的类包括LocalDateLocalTimeLocalDateTimeZonedDateTime

在这篇博文中,我们将总结讲解一些常用的日期处理操作,证明Java 8使用全新的LocalDateTime等类来替代以前老的Date必要性。平时我们在使用Date处理日期时间或多或少都有感觉到繁琐不方便,甚至出现逻辑不对、线程安全等问题。因为Java 8之前提供的API存在设计缺陷和使用上的复杂性,不过幸好的是很多开源框架提供了对日期时间处理操作封装的工具类,平时操作计算日期时间时不需要自己实现,直接调用工具包封装的方法即可,这里给大家推荐下常用的:hutool日期工具包

2.Date处理日期存在哪些问题

首先我想说Java 8引入操作日期时间的全新API,肯定不是空虚来风,多此一举,画蛇添足的。肯定是为了解决以前Date处理日期的一些痛点问题而产生的。下面我们就来看看日常使用Date处理日期时间存在的问题

2.1 日期时间计算

在平时业务开发过程中,根据当前日期进行加减天数计算时一个很常见的逻辑处理,因为大家都知道Date中保存的是一个UTC时间戳,代表的是从 1970 年 1 月 1 日 0 点(Epoch 时间)到现在的毫秒数,所以很多同学计算日期时间时都喜欢转换为时间戳进行加减计算来获得结果时间戳之后再转换为日期(笔者刚刚工作时也喜欢这么干),这样计算就会踩坑了,例如计算30天以后得日期时间示例如下:

    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) throws InterruptedException {
        Date now = new Date();
        System.out.println("now: " + simpleDateFormat.format(now));
        // 加30天
        Date afterDate = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);
        System.out.println("afterDate: " + simpleDateFormat.format(afterDate));
    }

执行结果如下:

now: 2024-07-02 16:48:35
afterDate: 2024-06-12 23:45:48

加了30天日期反倒变早了???出现这个问题,这是因为时间戳now.getTime() + 30 * 24 * 60 * 60 * 1000 计算时 int 发生了溢出。计算表达式可以看出是在加一个int数,从而计算结果也变成一个int数从而导致数值溢出,解决该问题只需要计算时加上一个long数即可,1000变成1000L如下所示:

    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) throws InterruptedException {
        Date now = new Date();
        System.out.println("now: " + simpleDateFormat.format(now));
        // 加10天
        Date afterDate = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000L);
        System.out.println("afterDate: " + simpleDateFormat.format(afterDate));
    }

执行结果就对了。由此看出计算日期时间使用时间戳相加减是非常容易出现意想不到的问题的,不建议使用这种方式。Java 8之前建议使用 Calendar计算:

  /**
   * 加n天后的日期
   */
  public static Date addDays(Date date, int n) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);
    cal.add(Calendar.DAY_OF_YEAR, n);
    return cal.getTime();
  }

使用 Java 8 的日期时间类型,可以直接进行各种计算,更加简洁和方便:

    public static void main(String[] args) throws InterruptedException {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime localDateTime = now.plusDays(30);
        System.out.println(localDateTime);
    }

控制台直接打印如下:

2024-08-01T17:05:11.609

输出的就是我们常见的日期格式,比起Date类型的日期输出格式更加一目了然。

2.2 格式"YYYY-MM-dd"跨年问题

有段时间我收到了关于这个格式问题的大量博文推送,标题确实蛮引人好奇了,譬如“使用YYYY-MM-dd格式化,元旦假期期间老板让回公司改线上bug”等。首先我们我都知道关于日期时间的格式化一般通用格式是:yyyy-MM-dd HH:mm:ss

平时我们一般都不咋在意年份是大写的Y还是小写的y,我们比较关注的是大写M代表月份,小写m代表分钟。下面就来看看YYYY-MM-dd咋就跨年有问题了,话不多说上示例:

    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd");

    public static void main(String[] args) throws InterruptedException {
        Calendar c = Calendar.getInstance();
        // 2023-12-30 周六
        c.set(2023, 11, 30);
        System.out.println(simpleDateFormat.format(c.getTime()));
        // 2023-12-31 周日
        c.set(2023, Calendar.DECEMBER, 31);
        System.out.println(simpleDateFormat.format(c.getTime()));
    }

执行结果如下:

2023-12-30
2024-12-31

是的你没看错,2023-12-31该日期格式化之后输出是2024-12-31,这就是所谓的跨年bug。产生问题的原因:小写 y 是年,而大写 Y 是 week year,也就是所在的周属于哪一年。当天所在的周属于的年份,一周从周日开始,周六结束,只要本周跨年,那么这周就算入下一年,这下清楚为啥这样了吧。确实Java 8之前日期格式平时一不留神就容易写错,产生这样的未知问题。

你可能还注意到月份枚举是从0到11,和我们平时使用的112月不对应,一般开发都建议枚举、常量等数值和数组下标一样从0开始,这本身没啥问题,JDK源码编写大佬也是这么干的,但是他有点忽略实际使用场景了,有点死脑筋的感觉了😄,这么说那`Calendar`源码大佬肯定要回怼了,我没让你直接写数字,你最好用我定义好的常量`Calendar.DECEMBER`不就不出问题了嘛~~嗯,有点道理,道理不大,Java 8提供的全新的日期时间API就是你的无声反驳啦。

2.3 SimpleDateFormat线程安全问题

Date类本身没有提供格式化和解析日期的直接支持。需要使用java.text.SimpleDateFormat类,这个类在多线程环境中也不是线程安全的,容易引发问题。示例如下:

    private static ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(20);
    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) throws InterruptedException {
        for ( int i = 0; i < 50; i++) {
            threadPoolExecutor.execute(() -> {
                try {
                    // 字符串解析转日期
                    System.out.println(simpleDateFormat.parse("2024-07-02 18:30:00"));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
    }

执行结果:

Tue Jul 02 18:30:00 CST 2024
Tue Jul 02 18:30:00 CST 2024
Fri Jul 02 18:30:00 CST 7024
Tue Jul 02 18:30:00 CST 2024
Tue Jul 02 18:30:00 CST 2024
Tue Jul 02 18:30:00 CST 2024
Mon Dec 02 18:18:00 CST 3
Mon Dec 02 18:18:00 CST 3
Thu Jul 02 18:30:00 CST 33
java.lang.NumberFormatException: empty String
	at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
	at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
	at java.lang.Double.parseDouble(Double.java:538)
	at java.text.DigitList.getDouble(DigitList.java:169)
	at java.text.DecimalFormat.parse(DecimalFormat.java:2089)
	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
	at java.text.DateFormat.parse(DateFormat.java:364)
	at com.shepherd.basedemo.date.DateTest.lambda$main$0(DateTest.java:34)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
java.lang.NumberFormatException: For input string: ".7024"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Long.parseLong(Long.java:578)
	at java.lang.Long.parseLong(Long.java:631)
	at java.text.DigitList.getLong(DigitList.java:195)
	at java.text.DecimalFormat.parse(DecimalFormat.java:2084)
	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
	at java.text.DateFormat.parse(DateFormat.java:364)
	at com.shepherd.basedemo.date.DateTest.lambda$main$0(DateTest.java:34)

可以看出有异常报错,正常解析转换的日期也有错误数据,这就是并发导致的。

调试代码直接来看看SimpleDateFormat#parse()方法会发现来到其父类DateFormat#parse():

    public Date parse(String source) throws ParseException
    {
        ParsePosition pos = new ParsePosition(0);
        Date result = parse(source, pos);
        if (pos.index == 0)
            throw new ParseException("Unparseable date: \"" + source + "\"" ,
                pos.errorIndex);
        return result;
    }

最终来到SimpleDateFormat#parse(),核心代码逻辑如下:

   @Override
    public Date parse(String text, ParsePosition pos)
    {
        CalendarBuilder calb = new CalendarBuilder()
        try {
            parsedDate = calb.establish(calendar).getTime();
        }
        return parsedDate;
    }

接下来看看CalendarBuilder是怎么构建Calender,核心代码逻辑如下:

Calendar establish(Calendar cal) {
        
        cal.clear();
        // Set the fields from the min stamp to the max stamp so that
        // the field resolution works in the Calendar.
        for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
            for (int index = 0; index <= maxFieldIndex; index++) {
                if (field[index] == stamp) {
                    cal.set(index, field[MAX_FIELD + index]); // 构建
                    break;
                }
            }
        }
        return cal;
    }

变量 calendarSimpleDateFormat对象一个字段属性,SimpleDateFormatparse 方法调用 CalendarBuilder#establish() 方法来构建calendarestablish 方法内部先清空 calendar 再构建 calendar,整个操作没有加锁。显然,如果多线程池调用parse方法,也就意味着多线程在并发操作一个 calendar,可能会产生一个线程还没来得及处理 calendar 就被另一个线程清空了了。解决办法要么把simpleDateFormat声明为方法内的局部变量,要么使用threadLocal来存放simpleDateFormat,每个线程有个数据副本进行c操作隔离。

    private static ThreadLocal<SimpleDateFormat> holder = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

使用 Java 8 中的 DateTimeFormatter就能解决上面日期时间格式化碰到的问题

    public static void main(String[] args) throws InterruptedException {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime localDateTime = LocalDateTime.parse("2024-07-02 18:30:22", formatter);
        System.out.println(localDateTime);
    }

总的来说,这些问题的存在就是Java 8引入全新api的大势所趋。

项目推荐:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企业级系统架构底层框架封装,解决业务开发时常见的非功能性需求,防止重复造轮子,方便业务快速开发和企业技术栈框架统一管理。引入组件化的思想实现高内聚低耦合并且高度可配置化,做到可插拔。严格控制包依赖和统一版本管理,做到最少化依赖。注重代码规范和注释,非常适合个人学习和企业使用

Github地址:https://github.com/plasticene/plasticene-boot-starter-parent

Gitee地址:https://gitee.com/plasticene3/plasticene-boot-starter-parent

微信公众号Shepherd进阶笔记

交流探讨qun:Shepherd_126

3.Java 8全新API是如何处理日期时间的

前面列举了使用Date操作日期时间存在总得的问题,所以如此说来这个Java 8提供全新日期时间处理类LocalDate、LocalDateTime等是非换不可了,LocalDateTime提供的处理日期时间的全新方法如下所示,可谓是应有尽有

接下来就来看看Java 8全新的API使用示例,带你丝滑上车。

3.1 获取当前日期时间

java.util.Date类是可变的,这意味着它的实例在创建之后可以被修改。这在多线程环境中会导致线程安全问题,而Java 8提供的所有日期时间类都是不可变的(LocalDateLocalTimeLocalDateTime等),从而保证了线程安全

  LocalDate today = LocalDate.now();
  System.out.println("Current date: " + today);
  LocalDateTime now = LocalDateTime.now();
  System.out.println("now: " + now);
  // 创建一个特定日期时间
  LocalDateTime specificDateTime = LocalDateTime.of(2024, 6, 13, 10, 15);
  System.out.println("Specific date and time: " + specificDateTime);
  // Date的可变性问题
  Date date = new Date();
  System.out.println("Original date: " + date);
  date.setTime(1000000000000L);
  System.out.println("Modified date: " + date);

执行结果如下所示:

Current date: 2024-07-04
now: 2024-07-04T10:00:52.201
Specific date and time: 2024-06-13T10:15
Original date: Thu Jul 04 10:00:52 CST 2024
Modified date: Sun Sep 09 09:46:40 CST 2001

可以看出Java 8提供的日期时间类输出格式更符合我们的日期使用习惯。

3.2 加减日期时间

上面我们分析了日期时间加减常见出现的问题,以及给出了合理的处理方式,这里我将再次全面带你掌握Java 8全新API加减日期时间的丝滑顺畅操作:

 // 当前日期
  LocalDate today = LocalDate.now();
  System.out.println("today: " + today);
  LocalDate localDate = today.plusDays(30);
  System.out.println("after 30 days: " + localDate);
  LocalDate weeks = today.plusWeeks(2);
  System.out.println("after 2 weeks: " + weeks);
  LocalDate months = today.minusMonths(3);
  System.out.println("before 3 months: " + months);
  LocalDate years = today.minusYears(5);
  System.out.println("before 5 years: " + years);
  today = today.plus(Period.ofDays(1)).minus(1, ChronoUnit.DAYS);
  System.out.println("plus 1 and minus 1, today: " + today);

  // 当前日期时间
  LocalDateTime now = LocalDateTime.now();
  System.out.println("now: " + now);
  LocalDateTime hours = now.plusHours(12);
  System.out.println("after 12 hours: " + 12);
  LocalDateTime minutes = now.minusMinutes(30);
  System.out.println("before 30 minutes: " + minutes);

执行结果如下:

today: 2024-07-04
after 30 days: 2024-08-03
after 2 weeks: 2024-07-18
before 3 months: 2024-04-04
before 5 years: 2019-07-04
plus 1 and minus 1, today: 2024-07-04
now: 2024-07-04T19:01:52.154
after 12 hours: 12
before 30 minutes: 2024-07-04T18:31:52.154

3.3 判断两个日期前后、相差天数、月份等

日常开发过程比较两个日期大小,计算两个日期相差多少天是一个常见的场景逻辑,所以下面来看看示例:

    LocalDate today = LocalDate.now();
    System.out.println("today: " + today);
    LocalDate date = LocalDate.of(2024, 7, 4);
    System.out.println("date: " + date);
    boolean b = today.equals(date);
    System.out.println("today 与 date是否相等:" + b);
    LocalDate afterDate = LocalDate.of(2024, 8, 10);
    boolean after = afterDate.isAfter(today);
    System.out.println("after today: " + after);
    LocalDate beforeDate = LocalDate.of(2024, 7, 3);
    boolean before = beforeDate.isBefore(today);
    System.out.println("before today: " + before);

    Period period = Period.between(today, afterDate);
    System.out.println("相差天数:" + period.getDays());
    System.out.println("相差月份:" + period.getMonths());

执行结果如下:

today: 2024-07-04
date: 2024-07-04
today 与 date是否相等:true
after today: true
before today: true
相差天数:6
相差月份:1

3.4 格式化日期时间

上面说了使用SimpleDateFormat存在线程安全问题,所以Java 8提供了DateTimeFormatter来格式化

  // 当前日期时间
  LocalDateTime now = LocalDateTime.now();

  // 定义格式化器
  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

  // 格式化日期时间
  String formattedDateTime = now.format(formatter);
  System.out.println("Formatted date and time: " + formattedDateTime);

  // 解析日期时间
  LocalDateTime parsedDateTime = LocalDateTime.parse(formattedDateTime, formatter);
  System.out.println("Parsed date and time: " + parsedDateTime);

执行结果如下:

Formatted date and time: 2024-07-04 20:43:01
Parsed date and time: 2024-07-04T20:43:01

3.5 综合小案例

需求是这样,输入一个号数day,判断day是否晚于当前日期,晚于则计算为当前月day日期,否则计算为下个月day日期,但要考虑计算结果月份是否有day日期?听不懂的话来看看例子,加入当前日期2024-08-04 ,输入day=3,则计算的结果日期为2024-09-03;输入day=5,则结果日期为2024-08-05,输入day=31,结果为日期为2024-09-30,因为9月份没有31号。

        int day = 3;
        // 获取当前日期的年和月、日
        LocalDate currentDate = LocalDate.now();
        int currentYear = currentDate.getYear();
        int currentMonth = currentDate.getMonthValue();
        int currentDay = currentDate.getDayOfMonth();
        // 计算下个月的年和月
        int nextMonth = currentMonth + 1;
        if (currentDay < day) {
            nextMonth = currentMonth;
        }
        int nextMonthYear = currentYear;
        if (nextMonth > 12) {
            nextMonth = 1;
            nextMonthYear = currentYear + 1;
        }
        // 获取下个月的YearMonth对象
        YearMonth nextYearMonth = YearMonth.of(nextMonthYear, nextMonth);
        // 获取下个月的天数
        int daysInNextMonth = nextYearMonth.lengthOfMonth();
        // 如果指定的日期超过了下个月的天数,则使用下个月的最后一天
        int dayToUse = Math.min(day, daysInNextMonth);
        LocalDate localDate = LocalDate.of(nextMonthYear, nextMonth, dayToUse);
        System.out.println(localDate);

3.6 Date与LocalDate、LocalDateTime互转

由于历史原因,在一个项目开发中既有用Date的,也有使用LocalDateTime的,所以必然存在互相转换的情况

    // 创建一个LocalDateTime对象
    LocalDateTime localDateTime = LocalDateTime.now();
    // 将LocalDateTime转换为Date
    Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    // 打印结果
    System.out.println("LocalDateTime: " + localDateTime);
    System.out.println("转换后的Date: " + date);

    // 创建一个LocalDateTime对象
    LocalDate localDate= LocalDate.now();
    // 将LocalDateTime转换为Date
    Date date1 = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
    // 打印结果
    System.out.println("LocalDateTime: " + localDateTime);
    System.out.println("转换后的Date1: " + date1);

    // 创建一个java.util.Date对象
    Date date2 = new Date();
    // 将Date转换为Instant
    Instant instant = date2.toInstant();
    // 获取系统默认时区
    ZoneId zoneId = ZoneId.systemDefault();
    // 将Instant转换为LocalDateTime
    LocalDateTime localDateTime2 = LocalDateTime.ofInstant(instant, zoneId);
    // 输出结果
    System.out.println("Date2: " + date);
    System.out.println("LocalDateTime2: " + localDateTime2);

4.总结

Java提供了多种方式来处理日期和时间,从早期的java.util.Datejava.util.Calendar到Java 8引入的现代化java.time下的全新API(LocalDate, LocalDateTime...)。新的API提供了更简单、直观且功能强大的日期时间处理能力,建议在新项目中尽量使用java.time包来进行日期时间操作。

无论是获取当前日期时间,创建特定的日期时间,还是进行日期时间的加减运算,Java的日期时间API都能提供全面的支持。同时,通过DateTimeFormatter类,还可以方便地对日期时间进行格式化和解析。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/773498.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

无线网卡怎么连接台式电脑?让上网更便捷!

随着无线网络的普及&#xff0c;越来越多的台式电脑用户希望通过无线网卡连接到互联网。无线网卡为台式电脑提供了无线连接的便利性&#xff0c;避免了有线网络的束缚。本文将详细介绍无线网卡怎么连接台式电脑的四种方法&#xff0c;包括使用USB无线网卡、内置无线网卡以及使用…

004 线程的状态

文章目录 Java线程可能的状态&#xff1a; 状态名称说明NEW初始状态&#xff0c;线程被构建&#xff0c;但是还没有调用start()方法RUNNABLE运行状态&#xff0c;Java线程将操作系统中的就绪和运行两种状态笼统地称作"运行中"BLOCKED阻塞状态&#xff0c;表示线程阻…

Websocket通信实战项目(图片互传应用)+PyQt界面+python异步编程(async) (上)服务器端python实现

Rqtz : 个人主页 ​​ 共享IT之美&#xff0c;共创机器未来 ​ Sharing the Beauty of IT and Creating the Future of Machines Together 目录 项目背景 ​编辑​专有名词介绍 服务器GUI展示 功能(位置见上图序号) 客户端GUI展示&#xff08;h5cssjs&#xf…

超融合服务器挂载硬盘--linux系统

项目中需要增加服务器的硬盘容量&#xff0c;通过超融合挂载了硬盘后&#xff0c;还需要添加到指定的路径下&#xff0c;这里记录一下操作步骤。 一&#xff1a;通过管理界面挂载硬盘 这一步都是界面操作&#xff0c;登录超融合控制云台后&#xff0c;找到对应的服务器&#…

Spring Boot 文件上传和下载指南:从基础到进阶

文章目录 引言1. 环境配置2. 文件上传2.1 配置文件上传路径2.2 创建上传服务2.3 创建上传控制器 3. 文件下载3.1 创建下载服务3.2 创建下载控制器 4. 前端页面4.1 文件上传页面4.2 文件下载页面 5. 技术分析结论 &#x1f389;欢迎来到SpringBoot框架学习专栏~ ☆* o(≧▽≦)o …

设置单实例Apache HTTP服务器

配置仓库 [rootlocalhost ~]# cd /etc/yum.repos.d/ [rootlocalhost yum.repos.d]# vi rpm.repo仓库代码&#xff1a; [BaseOS] nameBaseOS baseurl/mnt/BaseOS enabled1 gpgcheck0[AppStream] nameAppStream baseurl/mnt/AppStream enabled1 gpgcheck0挂载 [rootlocalhost …

数字IC设计-VCS和Verdi的使用

#学习记录# 前言&#xff1a;本文以一个简单的计数器来说明vcs和verdi的使用 1 代码文件 1.1 计数器代码 //Engineer&#xff1a;Mr-pn-junction module counter(input clk,input rst,output reg [5:0] count); always(posedge clk or negedge rst)beginif(!rst)coun…

BugkuCTF-Crypto(1-5)

题&#xff1a;抄错的字符 题目作者: Aman 题目描述:老师让小明抄写一段话&#xff0c;结果粗心的小明把部分数字抄成了字母&#xff0c;还因为强迫症把所有字母都换成大写。你能帮小明恢复并解开答案吗&#xff1a;QWIHBLGZZXJSXZNVBZW 分析&#xff1a; 数字和字符可能的转…

QTreeWidget的简单使用

使用 QTreeWidget 实现复杂树控件功能的详细教程_treewidget 加控件-CSDN博客 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QTreeWidget> namespace Ui { class MainWindow; }class MainWindow : public QMainWindow {Q_OBJECTpu…

鸿蒙开发——网络连接,axios第三方库

1. 下载和安装ohpm 为啥要安装ohpm呢&#xff0c;因为axios是第三方库&#xff0c;不是鸿蒙官方提供的&#xff0c;所以不能直接引入 ohmp简介&#xff1a;作为鸿蒙生态三方库的包管理工具&#xff0c;支持OpenHarmony共享包的发布、安装和依赖管理。 链接&#xff1a;ohpm命…

Python函数缺省参数的 “ 坑 ” (与C++对比学习)

我们都知道Python函数的缺省参数可以降低我们调用函数的成本&#xff0c;但是一般我们的缺省参数都是不可变对象&#xff0c;如果是可变对象&#xff0c;我们对其多次调用会发生什么呢&#xff1f; def func(arr[]):arr.append(Hello)print(arr)func() func() func() 这貌似…

不花钱如何让网站启用HTTPS访问

在互联网的世界里&#xff0c;数据安全已经成为了每个网站和用户都不得不面对的问题。近期&#xff0c;网络信息泄露事件频发&#xff0c;让越来越多的网站开始重视起用户数据的安全性&#xff0c;因此启用HTTPS访问成为了一个网站必须要部署的。 HTTPS协议&#xff0c;作为HT…

RestTemplate、MockMVC、Swagger

rest代码风格 硬编码的部分在实际开发中都是会替换成枚举对象 SpringMVC会自动把json格式的post请求转化为对应接收的 对象 响应请求时&#xff0c;也会自动把 对象转化为 json格式的 RestTemplate 浏览器的地址栏只能提供get请求访问后端&#xff0c;如果要使用post方式发送…

免费开源(附代码地址)文生图提示词自动优化,还发现三个小窍门,人大度小满等机构出品!阶跃星辰万亿MoE+多模态大模型矩阵亮相

免费开源(附代码地址)文生图提示词自动优化,还发现三个小窍门,人大度小满等机构出品!阶跃星辰万亿MoE+多模态大模型矩阵亮相。 文生图也有自己的prompt优化工具了。 我们都知道,大模型输出的质量,很大程度上依赖于输入的prompt。尤其在文生图领域,对于prompt格外敏感。…

Python内存优化的实战技巧详解

概要 Python是一种高级编程语言,以其易读性和强大的功能而广受欢迎。然而,由于其动态类型和自动内存管理,Python在处理大量数据或高性能计算时,内存使用效率可能不如一些低级语言。本文将介绍几种Python内存优化的技巧,并提供相应的示例代码,帮助在开发中更高效地管理内…

高职人工智能专业实训课之“生成对抗网络(GAN)”

一、前言 生成对抗网络&#xff08;GAN&#xff09;作为人工智能领域的一项重要技术&#xff0c;已经在图像生成、风格迁移、数据增强等多个领域展现出巨大的潜力和应用价值。为了满足高职院校对GAN专业实训课程的需求&#xff0c;唯众人工智能教学实训凭借其前沿的教育技术平…

Redis深度解析:核心数据类型与键操作全攻略

文章目录 前言redis数据类型string1. 设置单个字符串数据2.设置多个字符串类型的数据3.字符串拼接值4.根据键获取字符串的值5.根据多个键获取多个值6.自增自减7.获取字符串的长度8.比特流操作key操作a.查找键b.设置键值的过期时间c.查看键的有效期d.设置key的有效期e.判断键是否…

使用AES加密数据传输的iOS客户端实现方案

在现代应用开发中&#xff0c;确保数据传输的安全性是至关重要的。本文将介绍如何在iOS客户端中使用AES加密数据传输&#xff0c;并与服务器端保持加密解密的一致性。本文不会包含服务器端代码&#xff0c;但会解释其实现原理。 加密与解密的基本原理 AES&#xff08;Advance…

java+springboot+Mysql“友书”综合书籍平台系统24489-计算机毕业设计项目选题推荐(附源码)

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;“友书”综合书籍平台当然也不能排除在外。“友书”综合书籍平台系统是以实际运用为开发背景&#xff0c;运用软件工程原…

AI产品经理能力模型的重点素质:人文素养和灵魂境界

在AI产品经理的能力模型中&#xff0c;我最想提的差异化关键点&#xff0c;就是“人文素养和灵魂境界”。 1 为什么“人文素养和灵魂境界”非常重要&#xff1f; 一、“人文素养和灵魂境界”如何影响AI产品设计&#xff1f; 例1&#xff1a;面对一个具体的AI场景&#xff0…