赞
踩
day43
Stream(流)是数据渠道,用于操作数据源(集合、数组等),生成元素序列。换言之,集合是存储数据的容器,流使用操作这些数据的
Stream可以对集合进行非常复杂的查找、过滤、映射数据等操作,类似于SQL执行数据库查询。Stream提供了一种高效且易于使用的处理数据的方式
注意:
- Stream不会存储数据
- Stream不会改变源数据,通过一系列操作数据源会返回一个持有结果的新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); } }
注意:多个中间操作可以连接成一个流水线,除非流水线触发终止操作,否则中间操作不会执行任何的处理,而在终止操作时一次性全部处理,称为惰性求值/延迟加载
方法 | 描述 |
---|---|
filter(Predicate p) | 从流中排除元素 |
limit(long maxSize) | 设置限制数据条数 |
skip(long n) | 跳过元素,返回跳过n个元素的流,若流中不满足n个元素则返回空流。与limit()互补 |
distinct() | 筛选,流通过元素对象的hashCode()和equals()方法去除重复元素 |
如果没有终止操作,中间操作就不会被调用,终止操作时一次性全部处理,这种称为惰性求值/延迟加载
public class Test1 { 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("李四", 36, 7200,Course.JAVA)); @Test public void test01() { //需求1:过滤掉小于5000的学生对象 Stream<Student> stream = stuList.stream().filter((x)-> { System.out.println("中间操作"); return x.getSalary()>5000; }); //迭代输出流里的数据就等同于终止操作 //迭代功能在forEach()中完成,称为内部迭代(集合使用iterator()称为外部迭代) stream.forEach(System.out::println); } @Test public void test02() { //需求2:过滤掉小于5000的学生对象,并显示3条 //注意:因为限制了数据条数,所以满足数据条数后,后续的操作就不再运行了,效率就提高了 Stream<Student> stream = stuList.stream().filter((x)-> { System.out.println("短路"); return x.getSalary()>5000; }).limit(3); //迭代输出流里的数据就等同于终止操作 //迭代功能在forEach()中完成,称为内部迭代(集合使用iterator()称为外部迭代) stream.forEach(System.out::println); } @Test public void test03() { //需求3:过滤掉小于5000的学生对象,并跳过第1个学生对象 Stream<Student> stream = stuList.stream(). filter((x)-> x.getSalary()>5000). skip(1); //迭代输出流里的数据就等同于终止操作 //迭代功能在forEach()中完成,称为内部迭代(集合使用iterator()称为外部迭代) stream.forEach(System.out::println); } @Test public void test04() { //需求4:过滤掉小于5000的学生对象,并筛选掉重复元素 //Stream底层通过元素对象(Student对象)的hashCode()和equals()方法去除重复元素 Stream<Student> stream = stuList.stream(). filter((x)-> x.getSalary()>5000). distinct(); //迭代输出流里的数据就等同于终止操作 //迭代功能在forEach()中完成,称为内部迭代(集合使用iterator()称为外部迭代) stream.forEach(System.out::println); } } enum Course{//课程枚举 JAVA,HTML,PYTHON; } class Student{//学生类 private String name; private int age; private double salary; private Course course; ... }
方法 | 描述 |
---|---|
map(Function<?, ? > mapper) | 将流中所有元素映射成一个新的元素或者提取信息 |
flatMap(Function<?, ? extends Stream<? >> mapper) | 将流中的流整合(整合成平面/平铺流) |
public class Test1 { List<String> nameList = Arrays.asList("张三","李四","王五","赵六","孙七","吴八"); 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("李四", 36, 7200,Course.JAVA)); @Test public void test01() { //map() - 将流中所有元素映射成一个新的元素 或者 提取信息 //方式1:映射成一个新的元素 //需求://需求:nameList获取流对象,打印出所有学生的姓氏 nameList.stream().map((str)-> str.charAt(0)).forEach(System.out::println); //方式2:映射成提取信息 //需求:把原来流中的学生对象替换成学生姓名 stuList.stream().map((stu)-> stu.getName()).forEach(System.out::println); } @Test public void test02() { //带着需求学flatMap() //flatMap() - 将流中的流整合(整合成平面/平铺流) //需求:将nameList里的字符串转换为字符输出 //解决方案1:使用map()完成需求,可以看到流里包含另外的流,非常麻烦 Stream<Stream<Character>> stream = nameList.stream(). map(Test1::getCharacterStream);//{{'张','三'},{'李','四'},...} stream.forEach((sm) -> { sm.forEach(System.out::println); }); //解决方案2:使用flatMap()完成需求,将流中的流一并整合 nameList.stream().flatMap((str)-> getCharacterStream(str)). forEach(System.out::println);//{'张','三'},{'李','四'},... } //将字符串拆分出字符转换为流的方法 public static Stream<Character> getCharacterStream(String str){ ArrayList<Character> list = new ArrayList<>(); for (Character c : str.toCharArray()) { list.add(c); } return list.stream(); } } enum Course{//课程枚举 JAVA,HTML,PYTHON; } class Student{//学生类 private String name; private int age; private double salary; private Course course; ... }
继day42
方法 | 解释 |
---|---|
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类(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 } }
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 } }
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(); }
1.Stream的中间操作 - 排序
2.Stream的终止操作 – 匹配与查找
3.Stream的终止操作 – 归约
4.Stream的终止操作 – 收集
5.Stream的串行流和并行流
6.Optional
7.接口的类优先原则 和 接口冲突
8.日期时间组件
9.重复注解
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。