day43
JDK1.8新特性
Stream
简介
Stream(流)是数据渠道,用于操作数据源(集合、数组等),生成元素序列。换言之,集合是存储数据的容器,流使用操作这些数据的
Stream可以对集合进行非常复杂的查找、过滤、映射数据等操作,类似于SQL执行数据库查询。Stream提供了一种高效且易于使用的处理数据的方式
注意:
- Stream不会存储数据
- Stream不会改变源数据,通过一系列操作数据源会返回一个持有结果的新Stream
- Stream操作是延迟执行的,意味着流会等到需要结果的时候才执行
执行步骤
- 创建Stream:通过数据源(集合、数组等)获取一个Stream
- 中间操作:中间操作链,对源数据的数据进行处理
- 终止操作:执行中间操作,并产生结果
创建Stream
java
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()方法去除重复元素 |
如果没有终止操作,中间操作就不会被调用,终止操作时一次性全部处理,这种称为惰性求值/延迟加载
java
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) | 将流中的流整合(整合成平面/平铺流) |
java
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 |
不同条件排序,不同比较器,涉及前面比较器内容
java
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) | 返回流中最小值 |
所有终止操作都有返回值
匹配查找:使用方法有所差别
java
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) | 参数:(结合逻辑) |
JAVA
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有很多重载的方法【方法参数("分隔符","前缀或后缀")】
java
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并行计算框架
java
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返回的值可以是任意类型
java
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修饰的方法,此方法可以让接口的实现类所调用,而接
口中的静态方法直接用接口名调用即可
java
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{}
接口默认方法的"类优先"原则:
如果一个接口中定义了一个默认方法,而接口实现类的父类定义了一个同名的方法时,选择父类中的方法
接口冲突:如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突
java
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{}
java
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 | 针对时区操作的包 |
日期时间类、时间戳、间隔类
java
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
java
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
java
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
}
}
时区类
java
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:一个类可有多个同样的注解
java
@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.重复注解