day43
JDK1.8新特性
Stream
执行步骤
- 创建Stream:通过数据源(集合、数组等)获取一个Stream
- 中间操作:中间操作链,对源数据的数据进行处理
- 终止操作:执行中间操作,并产生结果
创建Stream
public class Test1 {
@Test
public void test01() {
//方式一:通过Collection接口提供的stream()-串行流或parallelStream()-并行流 获取流对象
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//方式二:通过Arrays的静态方法stream()获取流对象
String[] strs = new String[10];
Stream<String> stream2 = Arrays.stream(strs);
//方式三:通过Stream的静态方法of()获取流对象
Stream<String> stream3 = Stream.of("aaa","bbb","ccc");
//方式四:创建无限流
//iterate()迭代
Stream<Integer> stream4 = Stream.iterate(1, (x)->x+=100);
stream4.limit(3).forEach(System.out::println);
//方式五:创建无限流
Stream<Double> stream5 = Stream.generate(()->Math.random());
stream5.limit(3).forEach(System.out::println);
}
}
注意:多个中间操作可以连接成一个流水线,除非流水线触发终止操作,否则中间操作不会执行任何的处理,而在终止操作时一次性全部处理,称为惰性求值/延迟加载
中间操作 - 排序
| 方法 | 解释 |
|---|---|
| sorted() | 使用元素原有排序规则 - Comparable |
| sorted(Comparator<? super T> comparator) | 使用自定义排序规则 - Comparator |
不同条件排序,不同比较器,涉及前面比较器内容
public class Test01 {
List<Student> stuList = Arrays.asList(
new Student("张三", 28, 4800,Course.JAVA),
new Student("李四", 36, 7200,Course.JAVA),
new Student("王五", 19, 9600,Course.HTML),
new Student("赵六", 42, 6100,Course.HTML),
new Student("孙七", 23, 9600,Course.PYTHON),
new Student("吴八", 31, 3000,Course.PYTHON),
new Student("吴八", 31, 3000,Course.PYTHON));
@Test
public void test01(){
//需求:按照年龄排序 -- 内置比较器
stuList.stream().sorted().forEach(System.out::println);
}
@Test
public void test02(){
//需求:按照工资排序 -- 外置比较器
stuList.stream().sorted((stu1,stu2)->{
return Double.compare(stu1.getSalary(), stu2.getSalary());
}).forEach(System.out::println);
}
}
enum Course{//课程枚举
JAVA,HTML,PYTHON;
}
class Student implements Comparable<Student>{//学生类
private String name;
private int age;
private double salary;
...
}
终止操作 - 匹配与查找
| 方法 | 描述 |
|---|---|
| allMatch(Predicate<? super T> predicate) | 检查是否匹配所有元素 |
| anyMatch(Predicate<? super T> predicate) | 检查是否匹配至少一个元素 |
| noneMatch(Predicate<? super T> predicate) | 检查是否没有匹配所有元素 |
| findFirst() | 返回第一个元素 |
| findAny() | 返回任意一个元素(但效果不好) |
| count() | 返回流中元素的个数 |
| max(Comparator<? super T> comparator) | 返回流中最大值 |
| min(Comparator<? super T> comparator) | 返回流中最小值 |
所有终止操作都有返回值
匹配查找:使用方法有所差别
public class Test02 {
List<Student> stuList = Arrays.asList(
new Student("张三", 28, 4800,Course.JAVA),
new Student("李四", 36, 7200,Course.JAVA),
new Student("王五", 19, 9600,Course.HTML),
new Student("赵六", 42, 6100,Course.HTML),
new Student("孙七", 23, 9600,Course.PYTHON),
new Student("吴八", 31, 3000,Course.PYTHON),
new Student("吴八", 31, 3000,Course.PYTHON));
@Test
public void test01(){
//需求1:检查流中素所有元素是否匹配工资>5000
boolean bool = stuList.stream().allMatch((stu)->{
if(stu.getSalary() > 5000){
return true;
}
return false;
});
System.out.println(bool);
}
@Test
public void test02(){
//需求2:检查流中素所有元素至少匹配一个工资>5000
boolean bool = stuList.stream().anyMatch((stu)->{
if(stu.getSalary() > 5000){
return true;
}
return false;
});
System.out.println(bool);
}
@Test
public void test03(){
//需求3:检查流中素所有元素是否没有匹配 工资>5000
boolean bool = stuList.stream().noneMatch((stu)->{
if(stu.getSalary() > 5000){
return true;
}
return false;
});
System.out.println(bool);
}
@Test
public void test04(){
//需求4:返回工资最高的学生信息
Optional<Student> optional = stuList.stream().sorted((stu1,stu2)->{
return Double.compare(stu2.getSalary(), stu1.getSalary());
}).findFirst();
Student stu = optional.get();
System.out.println(stu);
}
@Test
public void test05(){
//需求5:返回随机学生信息(但效果不好)
Optional<Student> optional = stuList.stream().findAny();
Student stu = optional.get();
System.out.println(stu);
}
@Test
public void test06(){
//需求6:获取学生个数
long count = stuList.stream().count();
System.out.println(count);
}
@Test
public void test07(){
//需求7:获取最高工资的学生信息
Optional<Student> optional = stuList.stream().max((stu1,stu2)->Double.compare(stu1.getSalary(), stu2.getSalary()));
Student stu = optional.get();
System.out.println(stu);
}
@Test
public void test08(){
//需求8:获取最低工资的学生信息
Optional<Student> optional = stuList.stream().min((stu1,stu2)->Double.compare(stu1.getSalary(), stu2.getSalary()));
Student stu = optional.get();
System.out.println(stu);
}
}
enum Course{//课程枚举
JAVA,HTML,PYTHON;
}
class Student implements Comparable<Student>{//学生类
private String name;
private int age;
private double salary;
private Course course;
...
}
终止操作 - 归约
归约:将流中的元素反复结合起来,得到一个值
map+reduce的连接通常称为map_reduce模式,因Google用它进行网络搜索而出名
| 方法 | 描述 |
|---|---|
| reduce( T identity , BinaryOperator accumulator) | 参数:(初始值,结合逻辑) |
| reduce(BinaryOperator accumulator) | 参数:(结合逻辑) |
public class Test03 {
List<Integer> numList = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
List<Student> stuList = Arrays.asList(
new Student("张三", 28, 4800,Course.JAVA),
new Student("李四", 36, 7200,Course.JAVA),
new Student("王五", 19, 9600,Course.HTML),
new Student("赵六", 42, 6100,Course.HTML),
new Student("孙七", 23, 9600,Course.PYTHON),
new Student("吴八", 31, 3000,Course.PYTHON),
new Student("吴八", 31, 3000,Course.PYTHON));
@Test
public void test01(){
//需求1:获取numList集合中元素的总和
Integer sum = numList.stream().reduce(0, (x,y)->x+y);
System.out.println(sum);
}
@Test
public void test02(){
//需求2:获取stuList集合中所有学生工资总和
Optional<Double> optional = stuList.stream().map(Student::getSalary).reduce(Double::sum);
Double sum = optional.get();
System.out.println(sum);
}
}
enum Course{//课程枚举
JAVA,HTML,PYTHON;
}
class Student implements Comparable<Student>{//学生类
private String name;
private int age;
private double salary;
private Course course;
终止操作 - 收集
收集:将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
| 方法 | 描述 |
|---|---|
| collect(Collector<? super T, A, R> collector) | 把元素放入Collector集合中 |
补充:
收集比较麻烦
下面所做映射只能拿到单独的信息,获取更多信息就不用映射注意方法的使用,有些方法不熟悉就查API,ps:
分组注意方法选择【提示输入时】【多重分组】
joining有很多重载的方法【方法参数(”分隔符“,“前缀或后缀”)】
public class Test04 {
List<Student> stuList = Arrays.asList(
new Student("张三", 28, 4800,Course.JAVA),
new Student("李四", 36, 7200,Course.JAVA),
new Student("王五", 19, 9600,Course.HTML),
new Student("赵六", 42, 6100,Course.HTML),
new Student("孙七", 23, 9600,Course.PYTHON),
new Student("吴八", 31, 3000,Course.PYTHON),
new Student("吴八", 31, 3000,Course.PYTHON));
//将Stream中的数据收集到集合中----------------------------------------------------------
@Test
public void test01(){
//将Stream中的数据收集到List集合中
List<Student> list = stuList.stream().collect(Collectors.toList());
for (Student stu : list) {
System.out.println(stu);
}
}
@Test
public void test02(){
//将Stream中的数据收集到List集合中
Set<Student> set = stuList.stream().collect(Collectors.toSet());
for (Student stu : set) {
System.out.println(stu);
}
}
@Test
public void test03(){
//将Stream中的数据收集到指定集合中
LinkedList<Student> linkedList = stuList.stream().collect(Collectors.toCollection(LinkedList::new));
for (Student stu : linkedList) {
System.out.println(stu);
}
}
//收集流中各种数据 ----------------------------------------------------------
@Test
public void test04(){
//需求1:收集/获取学生个数
Long count = stuList.stream().collect(Collectors.counting());
System.out.println(count);
}
@Test
public void test05(){
//需求2:收集/获取学生平均工资
Double avg = stuList.stream().collect(Collectors.averagingDouble(Student::getSalary));
System.out.println(avg);
}
@Test
public void test06(){
//需求3:收集/获取学生总工资
Double sum = stuList.stream().collect(Collectors.summingDouble(Student::getSalary));
System.out.println(sum);
}
@Test
public void test07(){
//需求4:收集/获取学生工资最大值
Optional<Double> optional = stuList.stream().map(Student::getSalary).collect(Collectors.maxBy(Double::compareTo));
Double max = optional.get();
System.out.println(max);
}
@Test
public void test08(){
//需求5:收集/获取学生工资最小值
Optional<Double> optional = stuList.stream().map(Student::getSalary).collect(Collectors.minBy(Double::compareTo));
Double min = optional.get();
System.out.println(min);
}
@Test
public void test09(){
//需求6:收集/获取工资最多的学生信息
Optional<Student> optional = stuList.stream().collect(Collectors.maxBy((stu1,stu2)->{
return Double.compare(stu1.getSalary(), stu2.getSalary());
}));
Student stu = optional.get();
System.out.println(stu);
}
@Test
public void test10(){
//需求7:收集/获取工资最少的学生信息
Optional<Student> optional = stuList.stream().collect(Collectors.minBy((stu1,stu2)->{
return Double.compare(stu1.getSalary(), stu2.getSalary());
}));
Student stu = optional.get();
System.out.println(stu);
}
//分组收集 ----------------------------------------------------------
@Test
public void test11(){
//需求:按照学科分组
Map<Course, List<Student>> map = stuList.stream().collect(Collectors.groupingBy(Student::getCourse));
Set<Entry<Course,List<Student>>> entrySet = map.entrySet();
for (Entry<Course, List<Student>> entry : entrySet) {
System.out.println(entry);
}
}
@Test
public void test12(){
//需求:按照学科分组,在按照年龄分组
Map<Course, Map<String, List<Student>>> map = stuList.stream().collect(
Collectors.groupingBy(Student::getCourse,
Collectors.groupingBy((stu)->{
if(((Student)stu).getAge() < 28){
return "青年";
}else if(((Student)stu).getAge() < 40){
return "中年";
}else{
return "老年";
}
})));
Set<Entry<Course,Map<String,List<Student>>>> entrySet = map.entrySet();
for (Entry<Course, Map<String, List<Student>>> entry : entrySet) {
Course course = entry.getKey();
System.out.println(course);
Map<String, List<Student>> value = entry.getValue();
Set<Entry<String,List<Student>>> entrySet2 = value.entrySet();
for (Entry<String, List<Student>> entry2 : entrySet2) {
String key = entry2.getKey();
List<Student> value2 = entry2.getValue();
System.out.println(key + " -- " + value2);
}
}
}
//分区收集 ----------------------------------------------------------
@Test
public void test13(){
//需求:按照工资5000为标准分区
Map<Boolean, List<Student>> map = stuList.stream().collect(Collectors.partitioningBy((stu)->{
if(stu.getSalary() > 5000){
return true;
}
return false;
}));
Set<Entry<Boolean,List<Student>>> entrySet = map.entrySet();
for (Entry<Boolean, List<Student>> entry : entrySet) {
System.out.println(entry);
}
}
//获取元素中字段的各种信息 ----------------------------------------------------------
@Test
public void test14(){
//需求:获取学生工资信息,再获取总值、平均值、最大值、最小值
DoubleSummaryStatistics dss = stuList.stream().collect(Collectors.summarizingDouble(Student::getSalary));
System.out.println("总值:" + dss.getSum());
System.out.println("平均值:" + dss.getAverage());
System.out.println("最大值:" + dss.getMax());
System.out.println("最小值:" + dss.getMin());
}
//拼接信息 ----------------------------------------------------------
@Test
public void test15(){
//需求:拼接学生姓名
String str = stuList.stream().map(Student::getName).collect(Collectors.joining());
System.out.println(str);
}
@Test
public void test16(){
//需求:拼接学生姓名
String str = stuList.stream().map(Student::getName).collect(Collectors.joining("--"));
System.out.println(str);
}
@Test
public void test17(){
//需求:拼接学生姓名
String str = stuList.stream().map(Student::getName).collect(Collectors.joining("--", "aa", "bb"));
System.out.println(str);
}
}
enum Course{//课程枚举
JAVA,HTML,PYTHON;
}
class Student implements Comparable<Student>{//学生类
private String name;
private int age;
private double salary;
private Course course;
...
}
并行流与串行流
并行流就是把一个内容拆分成多个数据块,并用不同的线程分别处理每个数据块的流。Java8中将并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API可以声明性地通过 parallel() - 并行流 与sequential()-顺序流 之间进行切换。
注意
- 默认为顺序流/串行流
- 并行流一般在大数据搜索里使用到
- JDK1.8之前也有并行流,叫做Fork/Join并行计算框架
public class Test05 {
public static void main(String[] args) {
//需求:使用并行流计算1-10000000L之和
OptionalLong optionalLong = LongStream.range(1, 10000001L).////生成1-10000000的数流
parallel().//设置成并行流
reduce(Long::sum);//归约求总值
long sum = optionalLong.getAsLong();
System.out.println(sum);
}
}
Optional
Optional类(java. util. Optional)是一个容器类,代表一个存在或不存在的值,原来用null表示一个值不
存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常
此类的设计就是更好的避免空指针异常
| 方法 | 描述 |
|---|---|
| Optional.of(T t) | 创建一个Optional实例 |
| Optional.empty() | 创建一 个空的 Optional实例 |
| Optional.ofNullable(T t) | 若t不为null,创建Optional实例,否则创建空实例 |
| get() | 获取Optional实例里的对象 |
| isPresent() | 判断是否包含值 |
| orElse(T t) | 如果调用对象包含值, 返回该值,否则返回t |
| orElseGet(Supplier s) | 如果调用对象包含值,返回该值,否则返回s获取的值 |
| map(Function f) | 如果有值对其处理,并返回处理后的Optional,否则返回optional. empty() |
| flatMap(Function mapper) | 与map 类似,要求返回值必须是Optional |
map返回的值可以是任意类型
public class Test01 {
public static void main(String[] args) {
//将数据添加到Optional对象中
//Optional<String> optional = Optional.of("aaabbb");
//创建空内容的Optional对象
Optional<String> optional = Optional.empty();
method(optional);
}
public static void method(Optional<String> optional){
//获取Optional对象中的数据
//String str = optional.get();
//获取Optional对象中的数据,如果没有数据就返回默认值
String str = optional.orElse("默认值");
System.out.println(str);
}
}
public class Test02 {
@Test
public void test01() {
//创建一个Optional实例,把对象封装到Optional容器里
// Optional<Student> op = Optional.of(new Student("aaa", 26, 6666, Course.HTML));
//创建一个空的Optional容器
// Optional<Student> op = Optional.empty();
//创建一个Optional实例,若对象为null->创建空实例,若对象为不为null->创建Optional实例
Optional<Student> op = Optional.ofNullable(
new Student("bbb", 26, 7777, Course.PYTHON));
//判断容器里是否包含对象
if(op.isPresent()){//包含
System.out.println("获取容器里的对象:" + op.get().getName());
}else{//不包含
System.out.println("容器里的对象为null");
}
//如果容器里有对象就返回,否则就返回新对象
Student stu = op.orElse(new Student("ccc", 26, 8888, Course.JAVA));
System.out.println(stu.getName());
//不同情况下可以返回不同对象,orElseGet()比orElse()可变性更强
boolean bool = true;
stu = op.orElseGet(()->{
if(bool){
return new Student("吴彦祖", 26, 8888, Course.JAVA);
}else{
return new Student("麻生希", 26, 8888, Course.JAVA);
}
});
//获取原容器中的某个值并返回新容器中
//map(Function<? super T, ? extends U> mapper)
Optional<String> map = op.map(Student::getName);
System.out.println(map.get());
//与map 类似,要求返回值必须是Optional
//flatMap(Function<? super T, Optional<U>> mapper)
Optional<String> flatMap = op.flatMap((e)->Optional.of(e.getName()));
System.out.println(flatMap.get());
}
}
enum Course{//课程枚举
JAVA,HTML,PYTHON;
}
class Student implements Comparable<Student>{//学生类
private String name;
private int age;
private double salary;
private Course course;
...
}
接口的默认方法与静态方法
从JDK1.8开始,接口中可以有默认方法,既default修饰的方法,此方法可以让接口的实现类所调用,而接
口中的静态方法直接用接口名调用即可
public class Test1 {
@Test
public void test01() {
MyClass myClass = new MyClass();
myClass.defaultMethod();
I1.staticMethod();
}
}
interface I1{
default void defaultMethod(){
System.out.println("接口中的默认方法");
}
public static void staticMethod(){
System.out.println("接口中的静态方法");
}
}
class MyClass implements I1{}
接口默认方法的”类优先”原则:
如果一个接口中定义了一个默认方法,而接口实现类的父类定义了一个同名的方法时,选择父类中的方法
接口冲突:如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突
public class Test01 {
public static void main(String[] args) {
B b = new B();
b.method();
}
}
interface I1{
default void method(){
System.out.println("I1接口中的method方法");
}
}
class A{
public void method(){
System.out.println("A类中的method方法");
}
}
class B extends A implements I1{}
public class Test01 {
public static void main(String[] args) {
}
}
interface I1{
default void method(){}
}
interface I2 extends I1{
public void method();
}
class A implements I2{
@Override
public void method() {
}
}
日期组件
JDK1.8提供的新日期类都是不可变的,既不管怎么样的改变,都会产生一个新的实例,他们都是线程安全的
日期组件遵循与IOS-8601世界时间标准
组件简介
| 包路径 | 类名 | 描述 |
|---|---|---|
| java.time | 针对日期和时间操作的包 | |
| LocalDate | 用于表示日期的类 | |
| LocalTime | 用于表示时间的类 | |
| LocalDateTime | 用于表示日期时间的类 | |
| Instant | 时间戳类(1970.1.1 0:0:0 到现在的毫秒数) | |
| Period | 两个日期间隔类 | |
| Duration | 两个时间间隔类 | |
| java.time.chrono | 针对日期时间特殊格式操作的包 | |
| JapaneseChronology | 日本帝国历法系统类 | |
| ThaiBuddhistChronology | 泰国佛教日历系统类 | |
| java.time.format | 针对时间日期时间格式化操作的包 | |
| DateTimeFormatter | 格式化日期时间类 | |
| java.time.temporal | 针对时间矫正操作的包 | |
| java.time.zone | 针对时区操作的包 |
日期时间类、时间戳、间隔类
public class Test01 {
@Test
public void test01() {
//LocalDate LocalTime LocalDateTime
//这三个日期类的使用大致一样
//获取当前日期时间对象
LocalDateTime ldt1 = LocalDateTime.now();
System.out.println(ldt1);//2024-4-27T11:16:30.786
//获取指定日期时间对象
LocalDateTime ldt2 = LocalDateTime.of(2024, 1, 23, 8, 30, 10, 10);
System.out.println(ldt2);//2024-1-23T8:30:10.000000010
//获取ldt1推后的时间日期对象
LocalDateTime ldt3 = ldt1.plusYears(2);
System.out.println(ldt3);//2026-4-27T11:16:30.786
//获取ldt1提前的时间日期对象
LocalDateTime ldt4 = ldt3.minusMonths(2);//2026-2-27T11:16:30.786
//获取单个日期信息
System.out.println(ldt4.getYear());
System.out.println(ldt4.getMonthValue());
System.out.println(ldt4.getDayOfMonth());
System.out.println(ldt4.getHour());
System.out.println(ldt4.getMinute());
System.out.println(ldt4.getSecond());
}
@Test
public void test02() {
//使用时间戳(从1970年1月1日0:0:0到现在的毫秒值)
//默认创建UTC(世界标准时间)时区的时间戳对象
Instant now1 = Instant.now();
System.out.println(now1);//2024-04-27T03:19:19.352Z
//获取偏移8小时的偏移日期时间对象
OffsetDateTime odt = now1.atOffset(ZoneOffset.ofHours(8));
System.out.println(odt);//2024-04-27T11:19:19.352+08:00
//获取时间戳的毫秒值形式
System.out.println(now1.toEpochMilli());//1714187959352
//获取一个1970年1月1日0:0:0 往后退1秒的时间戳对象
Instant now2 = Instant.ofEpochSecond(1);
System.out.println(now2);//1970-01-01T00:00:01Z
}
@Test
public void test03() throws InterruptedException {
//Duration:时间间隔类
Instant now1 = Instant.now();
Thread.sleep(1000);
Instant now2 = Instant.now();
//获取时间间隔类对象
Duration duration1 = Duration.between(now1, now2);
System.out.println(duration1.toMillis());//1005
System.out.println("-----------------------------");
LocalTime lt1 = LocalTime.now();
Thread.sleep(1000);
LocalTime lt2 = LocalTime.now();
//获取时间间隔类对象
Duration duration2 = Duration.between(lt1, lt2);
System.out.println(duration2.toMillis());//1013
}
@Test
public void test04() throws InterruptedException {
//Period:日期间隔类
LocalDate ld1 = LocalDate.now();
Thread.sleep(1000);
LocalDate ld2 = LocalDate.of(2025, 12, 31);
Period period = Period.between(ld1, ld2);
System.out.println(period.getYears());//1
System.out.println(period.getMonths());//8
System.out.println(period.getDays());//4
}
}
日期时间格式化类-DateTimeFormatter
public class Test02 {
@Test
public void test01() {
//格式化日期时间类
LocalDateTime ldt1 = LocalDateTime.now();//2024-04-27T11:25:19.091
//获取本地标准的日期时间格式化对象
DateTimeFormatter dtf1 = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
String strDateTime1 = ldt1.format(dtf1);//格式化时间日期
System.out.println(strDateTime1);//2024-04-27T11:25:19.091
//自定义日期时间格式化对象
DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String strDateTime2 = ldt1.format(dtf2);//格式化时间日期
System.out.println(strDateTime2);//2024年04月27日 11:25:19
//将指定格式的字符串解析成LocalDateTime对象
LocalDateTime parse = LocalDateTime.parse("2024年04月27日 11:25:19", dtf2);
System.out.println(parse);//2020-03-12T11:04:14
}
}
时间矫正器类-TemporalAdjuster
public class Test03 {
@Test
public void test01() {
//时间矫正器
LocalDateTime ldt1 = LocalDateTime.now();//2024-04-27T11:25:19.091
//设置指定月份
LocalDateTime ldt2 = ldt1.withMonth(10);
System.out.println(ldt2);//2024-10-27T11:25:19.091
//设置下一个周末
LocalDateTime ldt3 = ldt1.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println(ldt3);//2024-04-28T11:27:41.517
//自定义时间矫正器:设置下一个工作
LocalDateTime ldt4 = ldt1.with((temporal)->{
LocalDateTime ldt = (LocalDateTime) temporal;
DayOfWeek week = ldt.getDayOfWeek();
if(week.equals(DayOfWeek.FRIDAY)){//周五
return ldt.plusDays(3);//往后推3天
}else if(week.equals(DayOfWeek.SATURDAY)){//周六
return ldt.plusDays(2);//往后推2天
}else{
return ldt.plusDays(1);//往后推1天
}
});
System.out.println(ldt4);//2024-04-29T11:28:55.733
}
}
时区类
public class Test04 {
@Test
public void test01() {
//时区类
//获取所有时区字符串
Set<String> set = ZoneId.getAvailableZoneIds();
for (String str : set) {
System.out.println(str);
}
System.out.println("---------------------------");
//获取指定时区的日期时间对象
LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println(ldt1);//2024-04-27T12:30:53.943
System.out.println("---------------------------");
//获取指定时区的日期时间对象 + 偏移量
LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
ZonedDateTime zonedDateTime = ldt2.atZone(ZoneId.of("Asia/Tokyo"));
System.out.println(zonedDateTime);//2024-04-27T12:30:53.943+09:00[Asia/Tokyo]
}
}
重复注解及类型注解
jdk1.8开始可以重复注解
ps:一个类可有多个同样的注解
@Author(name="张老师")
@Author(name="李老师")
public class Test01 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
Class<?> clazz = Test01.class;
//获取类上的注解
Author[] as = clazz.getDeclaredAnnotationsByType(Author.class);
for (Author author : as) {
System.out.println(author.name());
}
//获取参数上的注解
Method method = clazz.getMethod("method", String.class);
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
Author annotation = parameter.getAnnotation(Author.class);
System.out.println(annotation.name());
}
}
public void method(@Author(name="何老师") String str){}
}
//作者容器注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Authors {
Author[] value();
}
//作者注解
@Repeatable(Authors.class)//使用重复注解,就必须加上该注解
@Target({ElementType.TYPE,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
String name();
}

2738

被折叠的 条评论
为什么被折叠?



