JAVA快速入门到精通牛客零基础刷题指南:35~37 手把手带刷:常用API,日期工具

JAVA快速入门到精通牛客零基础刷题指南:35~37 手把手带刷:常用API,日期工具

常用API

日期工具

Date

Date类用来处理日期和时间,但是该类的大部分构造器、方法均以过时。

- 常用的构造方法
// 创建代表当前时间的Date对象,底层调用System类获取当前时间毫秒数。 public Date() { } // 根据指定的时间毫秒数创建Date对象,参数为时间的毫秒数。 public Date(long date) { }
- 常用的成员方法
// 判断该时间是否在指定时间之后 public boolean after(Date when) { } // 判断该时间是否在指定时间之前 public boolean before(Date when) { } // 返回该时间的毫秒数 public long getTime() { } // 以毫秒数的形式,设置该Date对象所代表的时间。 public void setTime(long time) { }

Calendar

  • 相比于Date类,Calendar类可以更好地处理日期和时间。
  • Calendar是一个抽象类,所以不能通过构造器创建Calendar对象。
  • Calendar类提供了静态方法getInstance(),用以创建实例。
- Calendar类提供了与Date互转的方法
// 返回Date public final Date getTime() { } // 将Date转为Calendar public final void setTime(Date date) { }
- Calendar类常用的成员方法
// 返回指定字段的值 public int get(int field) {} // 给指定的字段设置一个值 public void set(int field, int amount) {} // 设置年月日的值 public void set(int year, int month, int date) {} // 设置年月日时分秒的值 public void set(int year, int month, int date, int hourOfDay, int minute, int second) {}
- Calendar类常用的静态变量
YEAR, MONTH, DATE, HOUR, MINITE, SECOND, MILLISECOND

DateFormat

DateFormat用于实现日期的格式化,它是一个抽象类,提供了如下静态方法以创建实例:

// 返回日期格式器 public final static DateFormat getDateInstance() {} // 返回时间格式器 public final static DateFormat getTimeInstance() {} // 返回日期时间格式器 public final static DateFormat getDateTimeInstance() {}

同时,DateFormat提供了如下常用的成员方法:

// 将传入的日期格式化为字符串 public final String format(Date date) {} // 将传入的格式字符串解析为日期 public Date parse(String source) throws ParseException {}

SimpleDateFormat

SimpleDateFormat是DateFormat的子类,提供了更简单的格式化方案,该类提供了如下常用的构造器,常用的成员方法则与DateFormat一致。

// pattern是一个日期模板字符串,如“yyyy-MM-dd HH:mm:ss” public SimpleDateFormat(String pattern) {}

JAVA35 输出某一年的各个月份的天数

Calendar calendar=Calendar.getInstance(); for(int month=1;month<=12;month++){ calendar.set(year,month,0); System.out.println(year+"年"+month+"月:"+calendar.get(calendar.DAY_OF_MONTH)+"天"); }

DAY_OF_MONTHjava.util.Calendar 类的静态常量(int 类型)

Calendar 的月份是 0 基索引:0 代表 1 月,1 代表 2 月,……,11 代表 12 月,这是 Calendar 最经典的 “坑”

日期传入 0 的特殊规则:Calendar 的set方法中,日期字段传入0,代表取「上一个月的最后一天」

举个例子帮你理解:

  • month=1时,set(year, 1, 0) → 月份 1 对应日历的 2 月,日期 0 → 自动回退到 2 月的上一个月(1 月)的最后一天。
  • 此时调用get(Calendar.DAY_OF_MONTH),拿到的就是 1 月最后一天的数值,也就是 1 月的总天数。
  • 同理,month=12时,set(year,12,0) → 月份 12 对应次年 1 月,日期 0 → 回退到当年 12 月的最后一天,拿到 12 月的总天数。

JAVA36 日期换算

//将输入的日期用空格分割成字符串数组 String[] arr=str1.split(" "); //如果不是6位长度,则输入不正常 if(arr.length!=6){ System.out.println("您输入的数据不合理"); } else{ //将日期调整成"yyyy-MM-dd HH:mm:ss"的格式 String str=arr[0]+"-"+arr[1]+"-"+arr[2]+" "+arr[3]+":"+arr[4]+":"+arr[5]; //解析日期 Date date=sdf.parse(str); //输出北京时间 System.out.println("北京时间为:"+sdf.format(date.getTime())); //输出纽约时间 System.out.println("纽约时间为:"+sdf.format(date.getTime()-(long)12*60*60*1000)); }

parseSimpleDateFormat类的核心方法,作用是把符合指定格式的「日期时间字符串」,解析转换为java.util.Date日期对象,是「字符串→日期对象」的转换方法。

formatparse的反向操作,作用是Date对象 /long类型的时间戳,按照sdf指定的格式模板,转换为人类可读的日期时间字符串

强转long的 2 个核心原因
原因 1:从根源上规避整数溢出,是行业通用安全规范

如果不加强转,12*60*60*1000的所有操作数都是int,运算结果也是int。虽然 12 小时的毫秒数 43200000,刚好在int范围内,但这是非常脆弱的写法

  • 若后续修改数值(比如计算 30 天、100 天的毫秒数),30*24*60*60*1000=2592000000,已经超出int最大值,会直接溢出变成负数-1702967296,导致时间计算完全错误。

而把第一个数强转为(long)12后:

  • 第一个操作数变成long类型,后续所有乘法运算都会自动触发类型提升,全程以long类型运算,无论数值多大,都不会发生溢出。
  • 这是 Java 处理时间毫秒数的通用最佳实践,因为时间戳本身就是long类型,加减的数值也必须保证是long类型,从根源上避免 bug。
原因 2:和date.getTime()long类型匹配,避免隐式转换风险

date.getTime()返回的是long类型(64 位整数),如果减数是int类型,Java 会自动把int提升为long再做减法。

异常处理

  • Java语言具有如下的异常处理机制:当程序运行出现意外情形时,系统会自动生成一个异常对象来通知程序。
  • 在程序中,我们可以使用特定的语句来捕获异常对象,读取对象中的信息,进而做出处理。
  • 也可以使用特定的语句抛出异常对象,将这个异常对象交给程序的调用者处理。

异常的继承体系

- 所有的非正常情况被分为两类:

错误(Error)和异常(Exception),其中Error代表虚拟机相关问题,一般无法处理,也无需处理。

- 所有的 Exception 被分为两类
  • RuntimeException,代表运行时异常,程序可以显式处理这种异常,也可以不处理,而是交给顶层调用者统一处理。
  • 非运行时异常(Checked异常),程序必须显式地处理这种异常,否则在编译阶段会发生错误,导致程序无法通过编译。

捕获异常

语法:
try { 业务逻辑代码 } catch (AException e) { A异常的处理代码 } catch (BException e) { B异常的处理代码 } ... finally { 回收资源代码 }
说明:
1. 无论哪行代码发生异常,系统都会生成一个异常对象,这与try...catch...语句没有关系;

2. 若程序没有对这个异常对象做任何处理,则程序在此退出;

3. 创建异常对象后,JVM会寻找可以处理它的catch块,并将异常对象交给这个catch块去处理;

4. 程序应该先处理小异常、再处理大异常,即将处理父类异常的catch块放在处理子类异常的catch块之后;

5. finally块中代码总是会被执行,它必须位于try、catch之后,通常用来释放资源;

6. try是必须的,catch、finally是可选的,但catch、finally二者之中至少要出现一个。

声明抛出异常

语法:
throws ExceptionClass1, ExceptionClass2, ...
说明:
1. throws语句用于标识某方法可能抛出的异常,它必须位于方法签名之后;

2. throws语句声明抛出异常后,程序中旧无需使用try语句捕获该异常了;

3. 在重写时,子类方法声明抛出的异常类型不能比父类方法声明抛出的异常类型大。

抛出异常

语法:
throw ExceptionInstance;
说明:
1. throw语句用于在程序中主动抛出一个异常;

2. throw语句抛出的不是异常类型,而是一个异常实例;

3. 对于主动抛出的异常,也可以采用try块捕获,或者采用throws语句向外抛出。

异常的处理原则

1. 不要多度的使用异常:

不要用异常处理代替错误处理代码,不要用异常处理代替流程控制语句;

2. 不要忽略捕获的异常:

对于捕获到的异常,要进行合适的修复,对于不能处理的部分,应该抛出新的异常;

3. 不要直接捕获所有的异常:

应对不同的异常做出有针对性的处理,而捕获所有的异常,容易压制(丢失)异常;

4. 不要使用过于庞大的try块:

庞大的try块会导致业务过于复杂,不利于分析异常的原因,也不利于程序的阅读及维护。

JAVA37 判断学生成绩

import java.util.*; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int score = scanner.nextInt(); try{ //如果考试成绩在0-100之间,直接输出 if(score>=0&&score<=100){ System.out.println(score); } //否则抛异常 else{ throw new ScoreException("分数不合法"); } } //捕获到异常,输出错误信息 catch(ScoreException e){ System.out.println(e.getMessage()); } } } class ScoreException extends Exception{ //利用父类构造方法,初始化信息 ScoreException(String message){ super(message); } } 

getMessage():获取异常对象中携带的、自定义的异常详细描述文本

  • 当分数不合法时,new ScoreException("分数不合法") 会创建一个异常对象,把"分数不合法"通过构造方法,最终存到detailMessage里。
  • catch块捕获到这个异常对象,赋值给变量str
  • str.getMessage() 会读取异常对象里存储的detailMessage,也就是传入的"分数不合法",最终打印输出。
super(message) 的核心作用:“让父类帮忙初始化数据”

super 在这里的意思是 “父类的”,super(message) 就是 “调用父类中接收一个 String 参数的构造方法”。

public ScoreException(String message){ super(message); // 等价于:调用 Exception(String message) 这个构造方法 }
为什么必须写 super(message)?(不写会怎样?)

父类数据的封装性Throwable 里的 detailMessage 是一个 private(私有)变量。子类 ScoreException无权直接修改它。所以必须通过父类提供的 “构造方法入口”(即 super(message))来间接赋值。

如果不写,信息就丢了如果你只写 super()(不传参数),或者干脆不写 super(编译器会自动补一个无参的 super()),那么父类里的 detailMessage 就会是 null

super 关键字的两种常见用法

用法

示例

含义

1. 调用父类构造方法

super(message);

在子类构造方法的第一行调用,用于初始化父类的成员变量。

2. 调用父类的普通方法/变量

super.someMethod();

在子类方法中调用父类被重写(Override)的方法,或者访问父类的成员变量。

Read more

“现在的AI就像1880年的笨重工厂!”微软CSO斯坦福泼冷水:别急着造神

“现在的AI就像1880年的笨重工厂!”微软CSO斯坦福泼冷水:别急着造神

大模型仍未对上商业的齿轮? 编译 | 王启隆 来源 | youtu.be/aWqfH0aSGKI 出品丨AI 科技大本营(ID:rgznai100) 现在的硅谷,空气里都飘着一股“再不上车就晚了”的焦躁感。 最近 OpenClaw 风头正旺,强势登顶 GitHub,终结了 React 神话,许多人更是觉得“AI 自己干活赚钱”的日子就在明天了。 特别是在斯坦福商学院(GSB)这种地方,台下坐着的都是成天琢磨怎么用下一个技术风口搞个独角兽出来的狠人。 微软的首席科学官(CSO)Eric Horvitz 被请到了这个几乎全美最想用 AI 变现的礼堂里。作为从上世纪 80 年代就开始搞 AI 的绝对老炮、也是微软技术底座的“扫地僧”,这位老哥并没有顺着台下的胃口,去吹捧下个月大模型又要颠覆什么行业,而是兜头给大家浇了一盆带点学术味的冷水。 他讲了一个挺有画面感的比喻:大家都在聊

By Ne0inhk
Godot被AI代码“围攻”!维护者崩溃发声:“不知道还能坚持多久”

Godot被AI代码“围攻”!维护者崩溃发声:“不知道还能坚持多久”

整理 | 郑丽媛 出品 | ZEEKLOG(ID:ZEEKLOGnews) 当大模型能在几秒钟内生成一段“看起来像那么回事”的补丁时,开源社区却开始付出另一种代价。 最近,开源游戏引擎 Godot 的核心维护团队公开吐槽:他们正被大量“AI 生成的低质量代码”淹没。那些代码往往结构完整、注释齐全、描述洋洋洒洒,但真正的问题是——提交者可能并不理解自己交上来的内容。 这件事,并不是简单的“有人偷懒用 AI 写代码”。它正在触及开源协作最核心的东西:信任。 一场悄无声息的“AI 洪水” 事情的导火索来自一条 Bluesky 讨论帖。 Godot 主要维护者之一、同时也是 Godot 商业支持公司 W4 Games 联合创始人的 Rémi Verschelde 表示,所谓的“AI slop”

By Ne0inhk
诺奖得主辛顿最新访谈:1 万个 AI 可以瞬间共享同一份“灵魂”,这就是为什么人类注定被超越

诺奖得主辛顿最新访谈:1 万个 AI 可以瞬间共享同一份“灵魂”,这就是为什么人类注定被超越

当宇宙级的“嘴炮”遇到降维打击。 编译 | 王启隆 来源 | youtu.be/l6ZcFa8pybE 出品丨AI 科技大本营(ID:rgznai100) 打开最新一期知名播客 StarTalk 的 YouTube 评论区,最高赞的一条留言是这样写的: “我长这么大,第一次看到尼尔·德葛司·泰森(Neil deGrasse Tyson)在一档节目里几乎全程闭嘴,像个手足无措的小学生一样乖乖听讲。” 作为全美最知名的天体物理学家,泰森平时的画风是充满激情、喋喋不休、用宇宙的宏大来震撼嘉宾。但这一次,坐在他对面的那位满头银发、带着温和英音的英国老人,仅仅用最平淡的语气,就让整个演播室陷入了数次令人窒息的沉默。 这位老人是 Geoffrey Hinton。深度学习三巨头之一,2024 年诺贝尔物理学奖得主,被公认为“AI 教父”。 对经常阅读 Hinton 演讲的我来说,这也是比较新奇的一幕—

By Ne0inhk
48小时“烧光”56万!三人创业团队濒临破产,仅因Gemini API密钥被盗:“AI账单远超我们的银行余额”

48小时“烧光”56万!三人创业团队濒临破产,仅因Gemini API密钥被盗:“AI账单远超我们的银行余额”

整理 | 苏宓 出品 | ZEEKLOG(ID:ZEEKLOGnews) 「仅过了 48 小时,一笔 8.2 万美元的天价费用凭空出现,较这家小型初创公司的正常月费暴涨近 46000%。」 这不是假设的虚幻故事,而是一家墨西哥初创公司正在经历的真实危机。 近日,一位名为 RatonVaquero 的开发者在 Reddit 发帖求助称,由于他的 Gemini API 密钥被盗用,原本每月仅约 180 美元(约 1242 元)的费用,在短短 48 小时内暴涨到 82,314.44 美元(约 56.8 万元)。对于这家只有三名开发者的小型创业团队来说,这笔突如其来的账单,几乎等同于灭顶之灾。 “我现在整个人都处在震惊和恐慌之中。”RatonVaquero

By Ne0inhk