技术分享——Java8新特性
技术分享——Java8新特性
- 1.背景
- 2. 新特性主要内容
- 3. Lambda表达式
- 4. 四大内置核心函数式接口
- 4.1 Consumer<T>消费型接口
- 4.2 Supplier<T>供给型接口
- 4.3 Function<T,R>函数型接口
- 4.4 Predicate<T> 断定型接口
- 5. Stream流操作
- 5.1 什么是流以及流的类型
- 5.2 流操作
- 5.2.1 创建Stream
- 5.2.2 Stram流 筛选与切片
- 5.2.3 映射
- 5.2.4 排序
- 5.2.5 匹配与查找
- 5.2.6 规约与收集
- 6. 并行流 parallelStream
- 7. Optional 类
- 8. 新的时间API
- 8.1 java.time 主要类
- 8.2 应用对比
- 8.2.1 格式化对比
- 8.2.2 字符串转日期格式
- 8.2.3 日期计算
- 8.2.4 获取指定日期
1.背景
目前企业级开发语言主要是Java,Java 8 是目前最常用的 JDK 版本,相比 Java 7 增加了很多功能,比如 Lambda表达式、Stream 流操作、并行流(ParallelStream)、Optional 可空类型、新时间API等。
新特性给我们带来的好处
- 代码量更少(lambda表达式)
- 强大的Stream API(提供了一种新的处理集合数据的方式,允许以声明性的方式处理数据)
- 便于并行(ParallelStream)
- 最大化减少NPE(Optional)
2. 新特性主要内容
Lambda表达式
四大内置核心函数式接口
Stream流操作
ParallelStrean并行流
Optional类
新的时间API
3. Lambda表达式
Lambda表达式是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
- 语法格式
左侧:Lambda表达式的参数列表
右侧:Lambda表达式中所需执行的功能,既Lambda体 语法格式一:无参数,无返回值
Runnable r1 = ()-> System.out.println("Hello World");语法格式二:有一个参数,并无返回值
Consumer<String> con = (x)-> System.out.println(x);语法格式三:若只有一个参数,参数的()可以不写
Consumer<String> con = x-> System.out.println(x);语法格式四:有两个以上参数,有返回值,并且Lambda体中有多条语句
Comparator<Integer> com = (x, y) -> {System.out.println("Hello World");return Integer.compare(x, y);
};语法格式五:若Lambda体中只有一条语句,return和{}都可以不写
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
这里注意Lambda表达式需要"函数式接口"的支持。
函数式接口:接口中只有一个抽象方法,称为函数式接口(@FunctionalInterface 注解声明该接口是一个函数式接口)。
2. 举个🌰
匿名内部类的格式
new 父类或接口(){//进行方法重写
};// 用匿名内部类的方式来创建线程
new Thread(new Runnable() {@Overridepublic void run() {System.out.println("The runable now is using!");}
}).start();------------------------------------------------------------------------
// 使用Lambda来创建线程,返回的是Runnable对象实例
new Thread(() -> System.out.println("The runable now is using!")).start();
4. 四大内置核心函数式接口
4.1 Consumer消费型接口
接受一个参数,无返回值,常用于对参数进行处理、修改等操作。
举个🌰
public static void main(String[] args) {Consumer<Integer> consumer = i -> {System.out.println("Consumer 接收 参数 i 开始处理");int step = 1;System.out.printf("Consumer 输入%d, 输出%d%n", i, i + step);};List<Integer> list = Arrays.asList(4, 2, 6);list.forEach(consumer);
}
result:Consumer 接收 参数 i 开始处理Consumer 输入4, 输出5Consumer 接收 参数 i 开始处理Consumer 输入2, 输出3Consumer 接收 参数 i 开始处理Consumer 输入6, 输出7
4.2 Supplier供给型接口
不接受参数,返回一个结果,常用于生成某些对象。
举个🌰
// 获取长度为10的整数集合
public static List<Integer> getNumList(int num, Supplier<Integer> sup) {List<Integer> list = new ArrayList<>();for (int i = 0; i < num; i++) {Integer n = sup.get();list.add(n);}return list;
}getNumList(10, () -> (int) (Math.random() * 100));
4.3 Function<T,R>函数型接口
接受一个参数,返回一个结果,常用于对参数进行处理、转换等操作。
这里举个🌰
有User、UserEntity两个实体类定义如下
@Data
@AllArgsConstructor
public class User {private Integer age;private String name;
}
@Data
@AllArgsConstructor
public class UserEntity{private Integer age;private String name;private Integer type;
}
将一组User转换成一组UserEntity, 根据User的年龄来定义用户级别(普通用户,vip,svip),其中用户级别是User Entity的一个字段,所以输入参数是List,返回结果是List 。
构造数据
List<User> users = new ArrayList<>();
users.add(new User(10, "张三"));
users.add(new User(15, "李四"));
users.add(new User(16, "王五"));
users.add(new User(20, "赵六"));
users.add(new User(25, "田七"));
private static Function<List<User>, List<UserEntity>> multiUsersToEntities(List<User> users) {Function<List<User>, List<UserEntity>> function = t -> {List<UserEntity> userEntityList = new ArrayList<>();for (User user : t) {UserEntity userEntity = new UserEntity(user.getAge(), user.getName(), "普通用户");Integer age = user.getAge();if (age > 15 && age <= 20) {userEntity.setType("vip");}if (age > 20) {userEntity.setType("svip");}userEntityList.add(userEntity);}return userEntityList;};return function;
}List<UserEntity> uEntities = multiUsersToEntities(users).apply(users);
4.4 Predicate 断定型接口
接受一个参数,返回一个布尔值,常用于条件判断、筛选等操作。
Predicate<String> predicate = p -> p.length() == 21;
Stream<String> stream = stringList().stream().filter(predicate);
总结:
这四个接口的作用在于提供常用的函数式编程中常用的基础操作,提高了代码的复用性和简洁性。它们可以被Java8中的Lamba表达式直接调用,从而实现更加简洁而清晰的代码。
如果你需要进行一些简单的操作,这些接口可以让你无需自己编写函数或者创建单独的类,而使用Java8提供的函数式编程工具来解决问题。
除了四大核心函数接口外,Java8还提供了一些其他的函数式接口。
5. Stream流操作
5.1 什么是流以及流的类型
流是Java API的新成员,它允许通过声明的方式处理数据集合。我们可以把他看成遍历数据集的高级迭代器。它的源数据可以是 Collection、Array 等。由于它的方法参数都是函数式接口类型,所以一般和 Lambda 配合使用。
流的类型有stream 串行流和parallelStream 并行流,parallelStream可多线程执行。
特点:
- Stream不会自己存储元素
- Stream不会改变源对象,相反他们会返回一个持有新结果的新Strream。
- Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
5.2 流操作
Stram的操作三个步骤
- 创建Stream
一个数据源(如:集合、数组),获取一个流。 - 中间操作
一个中间操作,对数据源的数据进行处理。中间操作可以连成一条流水线。 - 终端操作
一个终端操作,执行中间操作链,并产生结果。终端操作的作用是关闭流水线。
5.2.1 创建Stream
- Collection系列集合提供的stream()方法或者parallelStream()创建Stream
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
- Arrays类中的静态方法stream()
Employee[] emps = new Employee[10];
Stream<Employee> stream = Arrays.stream(emps);
- 通过Stream类中的静态方法of
Stream<String> stream = Stream.of("aa", "bb", "cc");
5.2.2 Stram流 筛选与切片
- filter——接收Lambda, 从流中排除某些元素
Stream<T> filter(Predicate<? super T> predicate); 断言型接口
List<String> s = Arrays.asList("a","b","c",null);List<String> s2 = s.stream().filter(e -> e != null).collect(Collectors.toList());
System.out.println(s2);
// result:[a, b, c]
- limit ——截断流,使其不超过给定的数量
List<String> s = Arrays.asList("a","b","c");List<String> s2 = s.stream().limit(2L).collect(Collectors.toList());
System.out.println(s2);
// result:[a, b]
- skip(n)—— 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流
List<String> s = Arrays.asList("a","b","c");List<String> resultList = demoList.stream().skip(2).collect(Collectors.toList());
System.out.println(resultList);
// result: [c]
- distinct——筛选,通过流所生成元素的hashCode()和equals()去除重复元素
List<String> s = Arrays.asList("a","a","b","c");List<String> resultList = s.stream().distinct().collect(Collectors.toList());
System.out.println(resultList);
// result: [a,b,c]
5.2.3 映射
- map——支持Lambda语法,将元素转换成其他形式提取信息。接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
List<String> demoList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");List<String> result = demoList.stream().map(str -> str.toUpperCase()).collect(Collectors.toList());
System.out.println(result);
// result: [AAA, BBB, CCC, DDD, EEE]
- flatMap——将流中的每个值都替换成另一个流,然后把所有的流连接成一个流。
举个🌰
给定的单词集合[hello,world],返回集合[h,e,l,l,o, w,o,r,l,d]
List<String> stringList = Arrays.asList("hello", "world");
List<String[]> collect = stringList.stream().map(str -> str.split("")).collect(Collectors.toList());
collect.forEach(col -> System.out.println(Arrays.toString(col)));/* result:[h, e, l, l, o][w, o, r, l, d]
*/
大家可以看到返回结果是两个数组,并没有达到我们的要求。map的操作只是将元素放入map中的函数中使其返回另一个Stream<String[]>类型的,但我们真正想要的是一个Stream类型的,所以我们需要扁平化处理,将多个数组放入一个数组中。
List<String> stringList = Arrays.asList("hello", "world");
List<String> collect = stringList.stream().map(str -> str.split("")).flatMap(item -> {return Arrays.stream(item);}).collect(Collectors.toList());System.out.println(collect);// result:[h, e, l, l, o, w, o, r, l, d]
5.2.4 排序
- sorted()——自然排序(实现Comparable的compareTo方法)
List<String> list = Arrays.asList("ccc", "aaa", "bbb", "ddd", "eee");
list.stream().sorted().forEach(System.out::println);/* result: aaabbbcccdddeee
*/
- sorted(Comparator com)——定制排序
Stream<T> sorted(Comparator<? super T> comparator);
List<Employee> employeeList = new ArrayList<Employee>();
employeeList.add(new Employee(15, "18801171255", "张三", 8000));
employeeList.add(new Employee(18, "18801171256", "李四", 9000));
employeeList.add(new Employee(20, "18801171257", "王五", 1000));
employeeList.add(new Employee(20, "18801171258", "赵六", 1000));employeeList.stream().sorted((e1,e2)->{if(e1.getAge().equals(e2.getAge())){return e1.getName().compareTo(e2.getName());}else{return e1.getAge().compareTo(e2.getAge());}}).collect(Collectors.toList());System.out.println(employeeList);
/*retult:[Employee{age=15, mobile='18801171255', name='张三', salary=8000}, Employee{age=18, mobile='18801171256', name='李四', salary=9000}, Employee{age=20, mobile='18801171257', name='王五', salary=1000}, Employee{age=20, mobile='18801171258', name='赵六', salary=1000}]
*/
5.2.5 匹配与查找
- allMatch——检查是否匹配所有元素
判断数据列表中全部元素都符合设置的predicate条件,如果是就返回true,否则返回false,流为空时总是返回true。
boolean allMatch(Predicate<? super T> predicate);
List<String> typeList1 = Arrays.asList("1", "2");
List<String> typeList2 = Arrays.asList("1", "2", "3", "4");
// 集合列表中全部元素必须在allMatch里面的那些字符串,只要全部元素中有任意一个不同的元素在AllMatch中就返回false
boolean isMatch1 = typeList1.stream().allMatch(a -> a.equals("1") || a.equals("2") || a.equals("3"));
boolean isMatch2 = typeList2.stream().allMatch(a -> a.equals("1") || a.equals("2") || a.equals("3"));
System.out.println(isMatch1); // result:true
System.out.println(isMatch2); // fresult:false
- anyMatch——检查是否至少匹配一个元素(只要有一个满足条件就返回true)
List<Integer> list = Arrays.asList(10, 12, 14, 16);
boolean flag = list.stream().anyMatch(item -> item > 13);
System.out.println(flag); // result:true
- noneMath——检查是否没有匹配所有元素
判断数据列表中全部元素都不符合设置的predicate条件,如果是就返回true,否则返回false,流为空时总是返回true。
List<String> list = Arrays.asList("dddd", "ee", "qqq", "bcfff");
boolean isMatch = list.stream().noneMatch(str -> str.startsWith("a"));
System.out.println(isMatch); // result:true
- findFirst——返回第一个元素
Optional<T> findFirst();
List<String> list = Arrays.asList("dddd", "ee", "qqq", "bcfff");
Optional<String> result = list.stream().findFirst();
System.out.println(result.get()); // result:dddd
- findAny——返回当前流中的任意元素。返回的元素是不确定的,对于同一个列表多次调用findAny()有可能会返回不同的值。
- count——返回流中元素的总个数
- max——返回流中最大值、min——返回流中最小值
List<Employee> employeeList = new ArrayList<Employee>();
employeeList.add(new Employee(15, "18801171255", "张三", 8000));
employeeList.add(new Employee(18, "18801171256", "李四", 9000));
employeeList.add(new Employee(20, "18801171257", "王五", 1000));
employeeList.add(new Employee(30, "18801171258", "赵六", 1000));Employee maxAgeemployee = employeeList.stream().max((e1, e2) -> Integer.compare(e1.age, e2.getAge())).get();
System.out.println(maxAgeemployee);
// result:Employee{age=30, mobile='18801171258', name='赵六', salary=1000}Employee minAgeemployee = employeeList.stream().min((e1, e2) -> Integer.compare(e1.age, e2.getAge())).get();
System.out.println(minAgeemployee);
// result:Employee{age=15, mobile='18801171255', name='张三', salary=8000}
5.2.6 规约与收集
- Reduce——它将所有元素组合成单个结果。Reduce的目的是提供一种累积元素的方法,将所有元素组合为同一结果,可以使用reduce进行sum,min,max,count等操作
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = list.stream().reduce(0, (x, y) -> x + y);
System.out.println(sum); // result: 55
- 收集 collect——将流转化为其他形式。接收一个Collector接口的实现。Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map)。但是Collectors实用类提供了很多静态方法,可以方便地创建常见的收集器实例。
List<Employee> employeeList = new ArrayList<Employee>();
employeeList.add(new Employee(15, "18801171255", "张三", 8000));
employeeList.add(new Employee(18, "18801171256", "李四", 9000));
employeeList.add(new Employee(20, "18801171257", "王五", 1000));
employeeList.add(new Employee(30, "18801171258", "赵六", 1000));// 把名字收集成List集合
List<String> nameList = employeeList.stream().map(Employee::getName).collect(Collectors.toList());// 把年龄收集成set集合
Set<Integer> ageList = employeeList.stream().map(Employee::getAge).collect(Collectors.toSet());// 收集成Map key:age value:mobile
Map<Integer, String> ageAndMobileMap = employeeList.stream().collect(Collectors.toMap(Employee::getAge, Employee::getMobile));
6. 并行流 parallelStream
并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。
Java8中将并行流进行了优化,我们可以很容易的对数据进行并行操作,Stream API 可以声明性地通过parallel()与sequential()在并行流与顺序流之间进行切换。
这里举个🌰
Integer sum = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8).parallelStream().reduce(0, Integer::sum);
注意:
- 顺序问题
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);list.parallelStream().forEach(System.out::print);
// 65148723list.stream().forEach(System.out::print);
// 12345678list.parallelStream().forEachOrdered(System.out::print);
// 12345678
- 线程安全问题
public static void main(String[] args) {printFun();
}
public static void printFun() {List<Integer> integersList = new ArrayList<>();for (int i = 0; i < 100; i++) {integersList.add(i);}//普通集合 存储List<Integer> parallelStorage = new ArrayList<>();//同步集合 存储List<Integer> parallelStorage2 = Collections.synchronizedList(new ArrayList<>());//通过并行流存入普通集合parallelStorage中integersList.parallelStream().filter(i -> i % 2 == 0).forEach(i -> parallelStorage.add(i));System.out.println("开始打印普通集合parallelStorage");parallelStorage.stream().forEach(e -> System.out.print(e + " "));System.out.println();System.out.print("------------------------------------");System.out.println();//通过并行流存入同步集合parallelStorage2中integersList.parallelStream().filter(i -> i % 2 == 0).forEach(i -> parallelStorage2.add(i));System.out.println("开始打印同步集合parallelStorage");parallelStorage2.stream().forEach(e -> System.out.print(e + " "));
}
List<String> resultList = new CopyOnWriteArrayList<>();
List<String> resultList = Collections.synchronizedList(new ArrayList<>());
7. Optional 类
Optional<T>
类(java.util.Optional)是一个容器类,代表一个值存在或者不存在,原来用null表示一个值不存在,现在Optional可以更好的表达这个概念,并且可以避免空指针异常。
常用方法:
- Optional.of(T t):创建一个Optional实例
Optional<Person> op = Optional.of(new Employee());
op.get();
- Optional.empty():创建一个空的Optional实例
Optional op = Optional.empty();
op.get();
// NoSuchElementException
- Optional.ofNullable(T t):若t不为null,创建Optional实例否则创建空实例
Optional<Person> op = Optional.ofNullable(new Employee());
System.out.println(op.get());
// result: Employee{age=null, mobile='null', name='null', salary=null}
- orElse(T t):如果调用对象包含值,返回该值,否则返回t
Optional<Employee> op = Optional.ofNullable(null);
Employee employee = op.orElse(new Employee(15, "18801171255", "张三", 8000));
System.out.println(employee);
// result: Employee{age=15, mobile='18801171255', name='张三', salary=8000}
- orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回s获取到的值
Optional<Employee> op = Optional.ofNullable(null);
Employee employee = op.orElseGet(() -> new Employee(15, "18801171255", "张三", 8000));
System.out.println(employee);
// result: Employee{age=15, mobile='18801171255', name='张三', salary=8000}
- map(Function f):如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()
Optional<Employee> op = Optional.ofNullable(new Employee(15, "18801171255", "张三", 8000)));
Optional<String> opStr = op.map(e -> e.getName());
System.out.println(opStr.get());
// result:张三
- flatMap(Function mapper):与map类似,要求返回值必须是Optional
Optional<Employee> op = Optional.ofNullable(new Employee(15, "18801171255", "张三", 8000));
Optional<String> opStr = op.flatMap(e -> Optional.of(e.getName()));
System.out.println(opStr.get());
// result:张三
8. 新的时间API
8.1 java.time 主要类
LocalDateTime.class //日期+时间 format: yyyy-MM-ddTHH:mm:ss.SSS
LocalDate.class //日期 format: yyyy-MM-dd
LocalTime.class //时间 format: HH:mm:ss
8.2 应用对比
8.2.1 格式化对比
Java 8 之前:
import java.text.SimpleDateFormat;
import java.util.Date;public void oldFormat(){Date now = new Date();//format yyyy-MM-dd HH:mm:ssSimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");String date = sdf.format(now);System.out.println(String.format("date format : %s", date));result: date format : 2023-03-14
------------------------------------------------------------------//format HH:mm:ssSimpleDateFormat sdft = new SimpleDateFormat("HH:mm:ss");String time = sdft.format(now);System.out.println(String.format("time format : %s", time));result: time format : 15:45:32
------------------------------------------------------------------//format yyyy-MM-dd HH:mm:ssSimpleDateFormat sdfdt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String datetime = sdfdt.format(now);System.out.println(String.format("dateTime format : %s", datetime));dateTime format : 2023-03-14 15:45:32
}
Java 8 之后:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;public void newFormat(){//format yyyy-MM-ddLocalDate date = LocalDate.now();System.out.println(String.format("date format : %s", date));result:date format : 2023-03-14
------------------------------------------------------------------//format HH:mm:ssLocalTime time = LocalTime.now().withNano(0);System.out.println(String.format("time format : %s", time));result:time format : 15:49:16
------------------------------------------------------------------//format yyyy-MM-dd HH:mm:ssLocalDateTime dateTime = LocalDateTime.now();DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");String dateTimeStr = dateTime.format(dateTimeFormatter);System.out.println(String.format("dateTime format : %s", dateTimeStr));result:dateTime format : 2023-03-14 15:49:16
}
8.2.2 字符串转日期格式
Java 8 之前:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = sdf.parse("2022-09-20");
Java 8 之后:
public static LocalDate parse(CharSequence text) {return parse(text, DateTimeFormatter.ISO_LOCAL_DATE);
}
LocalDate.parse("2022-07-06");LocalDateTime.parse("2021-01-26 12:12:22");LocalTime.parse("12:12:22");
8.2.3 日期计算
Java 8 之前:
SimpleDateFormat formatDate = new SimpleDateFormat("yyyy-MM-dd");
Calendar ca = Calendar.getInstance();
ca.add(Calendar.DATE, 7);
Date d = ca.getTime();
String after = formatDate.format(d);
System.out.println("一周后日期:" + after);result:一周后日期:2023-03-21
-----------------------------------------------------------------------//算两个日期间隔多少天,计算间隔多少年,多少月方法类似
String dates1 = "2023-12-23";
String dates2 = "2023-02-26";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = format.parse(dates1);
Date date2 = format.parse(dates2);
int day = (int) ((date1.getTime() - date2.getTime()) / (1000 * 3600 * 24));
System.out.println(dates2 + "和" + dates2 + "相差" + day + "天");result:2023-02-26和2023-02-26相差300天
Java 8 之后:
public void pushWeek(){//一周后的日期LocalDate localDate = LocalDate.now();//方法1LocalDate after = localDate.plus(1, ChronoUnit.WEEKS);//方法2LocalDate after2 = localDate.plusWeeks(1);System.out.println("一周后日期:" + after);result:一周后日期:2023-03-21
-----------------------------------------------------------------------//算两个日期间隔多少天,计算间隔多少年,多少月LocalDate date1 = LocalDate.parse("2021-02-26");LocalDate date2 = LocalDate.parse("2021-12-23");Period period = Period.between(date1, date2);System.out.println("date1 到 date2 相隔:"+ period.getYears() + "年"+ period.getMonths() + "月"+ period.getDays() + "天");result:date1 到 date2 相隔:0年9月27天
------------------------------------------------------------------------- //这里period.getDays()得到的天是抛去年月以外的天数,并不是总天数//如果要获取纯粹的总天数应该用下面的方法long day = date2.toEpochDay() - date1.toEpochDay();System.out.println(date2 + "和" + date2 + "相差" + day + "天");result:2023-12-23和2023-12-23相差300天
}
8.2.4 获取指定日期
Java 8 之前:
public void getDay() {SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");//获取当前月第一天:Calendar c = Calendar.getInstance();c.set(Calendar.DAY_OF_MONTH, 1);String first = format.format(c.getTime());System.out.println("first day:" + first);//获取当前月最后一天Calendar ca = Calendar.getInstance();ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));String last = format.format(ca.getTime());System.out.println("last day:" + last);//当年最后一天Calendar currCal = Calendar.getInstance();Calendar calendar = Calendar.getInstance();calendar.clear();calendar.set(Calendar.YEAR, currCal.get(Calendar.YEAR));calendar.roll(Calendar.DAY_OF_YEAR, -1);Date time = calendar.getTime();System.out.println("last day:" + format.format(time));
}
Java 8 之后:
public void getDayNew() {LocalDate today = LocalDate.now();//获取当前月第一天:LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth());// 取本月最后一天LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth());//取下一天:LocalDate nextDay = lastDayOfThisMonth.plusDays(1);//当年最后一天LocalDate lastday = today.with(TemporalAdjusters.lastDayOfYear());//2023年最后一个周日,如果用Calendar是不得烦死。LocalDate lastMondayOf2023 = LocalDate.parse("2023-12-31").with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY));
}
相关文章:
![](https://img-blog.csdnimg.cn/202bf9370c0d4fad86b5131406be8072.png)
技术分享——Java8新特性
技术分享——Java8新特性1.背景2. 新特性主要内容3. Lambda表达式4. 四大内置核心函数式接口4.1 Consumer<T>消费型接口4.2 Supplier<T>供给型接口4.3 Function<T,R>函数型接口4.4 Predicate<T> 断定型接口5. Stream流操作5.1 什么是流以及流的类型5.2…...
![](https://www.ngui.cc/images/no-images.jpg)
vue基础知识大全
1,指令作用 以v-开头,由vue提供的attribute,为渲染DOM应用提供特殊的响应式行为,也即是在表达式的值发生变化的时候响应式的更新DOM。其内容为可以被求值的js代码,可以写在return后面被返回的表达式。 指令的简写指令简…...
![](https://img-blog.csdnimg.cn/b0f0bff7aca94ffbb7203bc01a43c374.png)
第2篇|文献研读|nature climate change|减缓气候变化和促进热带生物多样性的碳储量走廊
研究背景 从 2000 年到 2012 年,潮湿和干燥热带地区的森林总损失超过 90,000 平方公里 yr-1,这主要是由农业扩张驱动的。热带森林砍伐向大气中排放 0:95 Pg C yr-1 并导致广泛的生物多样性丧失。保护区的生物多样性取决于与保护区所在的更广泛景观的生态…...
![](https://img-blog.csdnimg.cn/img_convert/532108f1df0075b28e8890d6b9d70a71.png)
从暴力递归到动态规划(2)小乖,你也在为转移方程而烦恼吗?
前引:继上篇我们讲到暴力递归的过程,这一篇blog我们将继续对从暴力递归到动态规划的实现过程,与上篇类似,我们依然采用题目的方式对其转化过程进行论述。上篇博客:https://blog.csdn.net/m0_65431718/article/details/…...
![](https://www.ngui.cc/images/no-images.jpg)
Leetcode.1638 统计只差一个字符的子串数目
题目链接 Leetcode.1638 统计只差一个字符的子串数目 Rating : 1745 题目描述 给你两个字符串 s和 t,请你找出 s中的非空子串的数目,这些子串满足替换 一个不同字符 以后,是 t串的子串。换言之,请你找到 s和 t串中 恰…...
![](https://img-blog.csdnimg.cn/5a285a08269749caaecced56648116fb.png)
KoTime:v2.3.9新增线程管理(线程统计、状态查询等)
功能概览 KoTime的开源版本已经迭代到了V2.3.9,目前功能如下: 实时监听方法,统计运行时长web展示方法调用链路,瓶颈可视化追踪追踪系统异常,精确定位到方法接口超时邮件通知,无需实时查看线上热更新&…...
![](https://img-blog.csdnimg.cn/ce1dfec2e8084eb7b67689326637c038.png)
直面风口,未来不仅是中文版ChatGPT,还有AGI大时代在等着我们
说到标题的AI2.0这个概念的研究早在2015年就研究起步了,其实大家早已知道,人工智能技术必然是未来科技发展战略中的重要一环,今天我们就从AI2.0入手,以GPT-4及文心一言的发布为切入角度,来谈一谈即将降临的AGI时代。 关…...
![](https://img-blog.csdnimg.cn/9c9001627740413eaac8fba363fc4cc6.png)
若依微服务(ruoyi-cloud)保姆版容器编排运行
一、简介 项目gitee地址:https://gitee.com/y_project/RuoYi-Cloud 由于该项目运行有很多坑,大家可以在git克隆拷贝到本地后,执行下面的命令使master版本回退到本篇博客的版本: git reset --hard 05ca78e82fb4e074760156359d09a…...
![](https://img-blog.csdnimg.cn/e0950d57d0f149809560053994cea79e.gif#pic_center)
vue2图片预览插件
学习:vue插件开发实例-图片预览插件 vue2-pre-img-plugin的gitee代码 准备工作 准备图片与基础的样式 将iconfont下载的字体图标资源放在src/assets/iconfont目录下将准备预览的图片放到src/static/images目录下 PrevImg.vue 在plugins/PrevImg目录下ÿ…...
![](https://www.ngui.cc/images/no-images.jpg)
手写Promise源码的实现思路
Promise的使用: let promise new Promise((resolve, reject) > {resolve("OK");// reject("Error"); });console.log(promise);promise.then(value > {console.log("success"); }, error > {console.log("fail"…...
![](https://img-blog.csdnimg.cn/43a958f730f640c38e3b7c0827e2ddca.jpeg)
【数据结构】-关于树的概念和性质你了解多少??
作者:小树苗渴望变成参天大树 作者宣言:认真写好每一篇博客 作者gitee:gitee 如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧! 树前言一、树概念及结构1.1树的概念1.2 树的相关概念1.3 树的表示1.4树在实际中的运用…...
![](https://img-blog.csdnimg.cn/09d3697853a742b88b67892104483722.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5a2Z5LiN5Z2aMTIwOA==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
【前端之旅】NPM必知必会
一名软件工程专业学生的前端之旅,记录自己对三件套(HTML、CSS、JavaScript)、Jquery、Ajax、Axios、Bootstrap、Node.js、Vue、小程序开发(UniApp)以及各种UI组件库、前端框架的学习。 【前端之旅】Web基础与开发工具 【前端之旅】手把手教你安装VS Code并附上超实用插件…...
![](https://www.ngui.cc/images/no-images.jpg)
Android SQLite使用事务来确保所有语句都以原子方式执行及保证数据完整性一次执行多条语句示例
execSQL 不支持用分号分隔一次执行多个 SQL 语句,虽然理论上可以实现。但是,并不建议这样做,因为这可能会导致潜在的 SQL 注入漏洞。相反,建议使用 execSQL 或 rawQuery 分别执行每个语句。 在下面的代码块中,我们正在…...
![](https://img-blog.csdnimg.cn/92c3afdcc9af4004a3a86203dd912b84.jpeg)
nodejs+vue校园超市小卖部零食在线购物商城系统
21世纪的今天,随着社会的不断发展与进步,人们对于信息科学化的认识,已由低层次向高层次发展,由原来的感性认识向理性认识提高,管理工作的重要性已逐渐被人们所认识,科学化的管理,使信息存储达到…...
![](https://img-blog.csdnimg.cn/img_convert/2d8d44e514ab0e2ac15eaefe7161a3cd.jpeg)
Karl Guttag:论相机对焦技术在AR/VR中的沿用
近期,AR/VR光学专家Karl Guttag介绍了两家在CES 2023展出光学传感技术的公司:poLight和CML(剑桥机电一体化)。同时介绍两家公司的原因,是因为他们提供了实现AR/VR“光学微动”(Optics Micromovement&…...
![](https://img-blog.csdnimg.cn/img_convert/ebcb83f460d7494c647c82e7c279b691.png)
ECL@SS学习笔记(3)-概念数据模型
ECLSS 是产品,服务的分类和描述系统。本文介绍其内部的数据模型。ECLSS的作用ECLSS 标准的目标是为了实现工业界数据交换的标准化。这个标准主要作用是产品的分类和描述。分类为了有效地物料管理,供应链管理和电子商务,需要对物料进行分类和编…...
![](https://www.ngui.cc/images/no-images.jpg)
206. 反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1: 输入:head [1,2,3,4,5] 输出:[5,4,3,2,1] 示例 2: 输入:head [1,2] 输出:[2,1] 示例 3: 输…...
![](https://img-blog.csdnimg.cn/6f0c6dcff284477b8d28fa3526c95f37.png#pic_center)
文心一言 vs GPT-4 —— 全面横向比较
文心一言 vs GPT-4 —— 全面横向比较 3月15日凌晨,OpenAI发布“迄今为止功能最强大的模型”——GPT-4。我第一时间为大家奉上了体验报告《OpenAI 发布GPT-4——全网抢先体验》。 时隔一日,3月16日下午百度发布大语言模型——文心一言。发布会上&#…...
![](https://www.ngui.cc/images/no-images.jpg)
rancher2.6进阶之kubectl安装
rancher2.6进阶之kubectl安装 1.安装kubectl客户端 1.1.1.使用命令行下载安装包: curl -LO https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl Note: 可指定下载版本, 将 ( c u r l − L − s h t t p s : / / d l . k …...
![](https://img-blog.csdnimg.cn/img_convert/2d13aa9a455aefc53c3d1814634a15dc.png)
图像基本变换
缩放与裁剪裁剪图像的裁剪,是指将图像的某个区域切割出来。一些常见的应用场景包括:* 感兴趣区域提取* 去除无用信息* 图像增强* 纠偏:去除不规则部分,将图像变得更加整齐事实上,图像裁剪的裁剪通常就是一个numpy矩阵切…...
![](https://img-blog.csdnimg.cn/img_convert/07d6762d3491ecbcb67866b116c2f6e6.png)
基于文心一言的底层视觉理解,百度网盘把「猫」换成了「黄色的猫」
随着移动互联网的一路狂飙,手机已经成为人们的新器官。出门不带钥匙可以,不带手机却是万万不可以的。而手机上,小小的摄像头也越来越成为各位「vlogger」的口袋魔方。每天有超过数亿的照片和视频被上传到百度网盘中,这些照片和视频…...
![](https://img-blog.csdnimg.cn/011b1ec76eca4d64aed4fc626807e94e.png#pic_center)
安卓开发的环境配置教程
文章目录事先准备:下载 JDK、Gradle下载安装 Android Studio下载安装 Android SDK下载安装 ADB笔者的环境: Java 17.0.1 Gradle 8.0.1 Android Studio Electric Eel | 2022.1.1 Patch 1 Windows 10 教育版 64位 事先准备:下载 JDK、Gradl…...
![](https://www.ngui.cc/images/no-images.jpg)
【Spring Cloud Alibaba】Spring Cloud Alibaba 搭建教程
文章目录教程适用版本一、简介主要功能组件开源地址二、开始搭建1.项目搭建与依赖管理2.服务注册与发现(Nacos安装)3.创建服务提供者4.创建服务消费者5.创建服务消费者(Feign)6.添加熔断机制(Sentinel)7.Sentinel熔断器仪表盘监控…...
![](https://www.ngui.cc/images/no-images.jpg)
关于自动机器学习flaml训练时的一些报错
一、版本背景flaml 1.1.3sciket-learn 0.23.0二、一路报错2.1、SyntaxError: future feature annotations is not definedTraceback (most recent call last):File "C:/Users/dell/Desktop/AI/run.py", line 151, in <module>model.autoMlArgs(queryDf,targe…...
![](https://www.ngui.cc/images/no-images.jpg)
【计算机视觉】消融实验(Ablation Study)是什么?
文章目录一、前言二、定义三、来历四、举例说明一、前言 我第一次见到消融实验(Ablation Study)这个概念是在论文《Faster R-CNN》中。 消融实验类似于我们熟悉的“控制变量法”。 假设在某目标检测系统中,使用了A,B࿰…...
![](https://www.ngui.cc/images/no-images.jpg)
Java毕业论文参考文献参考例子整理
[1]李庆民.基于java的软件agent开发环境的分析[J].数字技术与应用,2017,01:189. [2]籍慧文.Web应用开发中JAVA编程语言的应用探讨[J].科技创新与应用,2017,07:90. [3]卜令瑞.基于Java软件项目开发岗位的企业实践总结报告[J].职业,2016,32:124-125. [4]肖成金,吕…...
![](https://www.ngui.cc/images/no-images.jpg)
C++ Primer第五版_第六章习题答案(21~30)
文章目录练习6.21练习6.22练习6.23练习6.24练习6.25练习6.26练习6.27练习6.28练习6.29练习6.30练习6.21 编写一个函数,令其接受两个参数:一个是int型的数,另一个是int指针。函数比较int的值和指针所指的值,返回较大的那个。在该函…...
![](https://img-blog.csdnimg.cn/img_convert/de3cfe830a8a17718894a93f2b831a4e.png)
SLAM算法之HectorSLAM,Gmapping,KartoSLAM,CoreSLAM和LagoSLAM
文章将介绍使用的基于机器人操作系统(ROS)框架工作的SLAM算法。 在ROS中提供的五种基于2D激光的SLAM算法分别是:HectorSLAM,Gmapping,KartoSLAM,CoreSLAM和LagoSLAM。当然最后还有比较经典的google开源的ca…...
![](https://img-blog.csdnimg.cn/d84db41f61534f9698bfd2f25b7eec52.jpeg)
phpstorm断点调试
环境:win10phpstorm2022phpstudy8lnmp 1、phpinfo(); 查看是否安装xdebug,没有走以下流程 2、phpstudy中切换不同版本php版本,有些版本不支持xdebug(如php8.0.2),有些已经自带了(如php7.3.9&a…...
![](https://img-blog.csdnimg.cn/8d2d37bb133149969c625331c87d287b.gif#pic_center)
做一个前端网页送给女朋友~轮播图+纪念日
文章目录1. 轮播图框架2. 轮播图大盒子实现1. 盒子及图片的可视化2. 将图片重叠起来并放入轮播图盒子中...相对定位与绝对定位3. 添加左右按钮4. 点击按钮跳转图片5. 鼠标离开图片轮播图按钮隐藏6. 添加小圆点按钮7. 点击小圆点跳转图片并且该小圆点变色8. 自动轮播9. 最后一步…...
![](https://images0.cnblogs.com/blog/75158/201301/29112942-1ad1dcf27bc44d57881e44baa6002235.jpg)
珠海中国建设银行招聘信息网站/国内5大搜索引擎
WCF由 .NET Framework 3.0 (大概在07年前后)开始引入,时隔五年多,才开始学习,再看到一些大牛在几年前已经 对WCF有比较深入了解,并写了不少博客,顿感学习之迟钝、技术之落伍——这其中有些人可能是对新技术的狂热和兴趣…...
![](/images/no-images.jpg)
乌兰察布做网站的公司/现在阳性最新情况
1、使用参数化SQL语句进行模糊查找的正确方法://定义sql语句string sql "SELECT StudentID,StudentNO,StudentName FROM Student WHERE StudentName like StudentName";//给参数赋值command.Parameters.AddWithValue("StudentName",txtStudent…...
![](https://img-blog.csdnimg.cn/img_convert/9f85251d51c8a583e05d0f8cb75bc935.png)
找人做网站一般要多少钱/宁德市人社局
详细内容Class c ArrayList.class;c.isPrimitive(); //判断c是否为基本数据类型c.isAssignableFrom(List.class); //判断c是否是List类的子类或父类c.getGenericType(); //得到泛型类型免费学习视频分享:java视频教程实例:通过反射得到List 集合中的泛型…...
![](/images/no-images.jpg)
网站要多钱/百度网站的网址
zip:压缩:zip [-AcdDfFghjJKlLmoqrSTuvVwXyz$][-b][-ll][-n][-t][-][压缩文件][文件...][-i][-x]解压:unzip[选项] 压缩文件名.zip选项:-x 文件列表解压缩文件,但不包括指定的file文件。-v 查看压缩文件目录,但不解压。…...
![](/images/no-images.jpg)
环保网站建设多少钱/轻松seo优化排名 快排
SC命令,与“服务控制器”和已安装设备进行通讯。SC.exe 检索和设置有关服务的控制信息。可以使用 SC.exe 来测试和调试服务程序。可以设置存储在注册表中的服务属性,以控制如何在启动时启动服务应用程序,以及如何将其作为后台程序运行。SC.ex…...
![](http://cn.wsj.com/photo/PJ-BR095A_WORKF_G_20131015222107.jpg)
网站建设区域加盟/100个裂变营销案例
十几岁的孩子常常会摔门、翻白眼,还会显出一副冷冰冰的样子,甚至连之前表现友善的孩子也是这样。一些家长会担心自己做错了什么,或者担心孩子会永远不考虑别人而只考虑自己。新的研究显示,这种现象归咎于生理,而不是家…...