JDK1.8新特性(剩余)【Stream;Optional;接口的类优先原则 和 接口冲突;日期时间组件 ;重复注解】--学习JavaEE的day43

发布于:2024-04-29 ⋅ 阅读:(44) ⋅ 点赞:(0)

day43

JDK1.8新特性

Stream

简介

Stream(流)是数据渠道,用于操作数据源(集合、数组等),生成元素序列。换言之,集合是存储数据的容器,流使用操作这些数据的

Stream可以对集合进行非常复杂的查找、过滤、映射数据等操作,类似于SQL执行数据库查询。Stream提供了一种高效且易于使用的处理数据的方式

注意:

  • Stream不会存储数据
  • Stream不会改变源数据,通过一系列操作数据源会返回一个持有结果的新Stream
  • Stream操作是延迟执行的,意味着流会等到需要结果的时候才执行
执行步骤
  1. 创建Stream:通过数据源(集合、数组等)获取一个Stream
  2. 中间操作:中间操作链,对源数据的数据进行处理
  3. 终止操作:执行中间操作,并产生结果
创建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()-顺序流 之间进行切换。

注意

  1. 默认为顺序流/串行流
  2. 并行流一般在大数据搜索里使用到
  3. 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();
}

总结

1.Stream的中间操作 - 排序

2.Stream的终止操作 – 匹配与查找

3.Stream的终止操作 – 归约

4.Stream的终止操作 – 收集

5.Stream的串行流和并行流

6.Optional

7.接口的类优先原则 和 接口冲突

8.日期时间组件

9.重复注解