Java8 新特性简介

目录

Java8新特性简介

一、Lambda表达式

1、Lambda表达式基础语法:

2、Lambda 表达式需要“函数式接口”的支持

二、函数式接口:Java8 内置的四大核心函数式接口

三、方法引用与构造器引用

四、Stream API

五、接口中的默认方法与静态方法

六、新时间日期API

七、Optional类

八、其他新特性


Java8新特性简介

  • 速度更快(红黑树)

底层数据结构,最核心的一个就是HashMap,那么HashMap给做了怎样的改动呢?

原来的HashMap是什么样的?为什么采用Hash表?如果HashMap不用Hash表的话,效率极低,因为每次添加元素都要与之前的元素挨个equals。因此Java工程师就采用Hash表(底层是个数组),这样有什么好处?既然底层都是数组,数组都有索引值。Map这个Hash表默认的大小是多少呢?默认是16。如果它采用这个Hash表的话,当我们要往里面添加一个对象的话,首先会调用我们这个对象的HashCode方法,然后根据Hash算法对这个HashCode进行运算,运算之后就是生成一个数组的索引值,根据这个索引值找到对应的位置,首先看那个位置有没有对象在,如果没有对象在,则直接存储;如果有对象存在,则需要用equals比较内容,如果内容一样,那么新值的value会覆盖旧值的value;如果内容不一样(这就是碰撞,尽量避免),则形成链表,jdk7中后加的节点放前面【头插法】,链表过长,效率低下。jdk8链表改为红黑树,链表与红黑树相比,除了插入效率高于红黑树,其他都没有红黑树的效率高;除此之外,扩容以后,这个树节点位置调整更加方便(原表长度+原来节点的hash表位置)

  • 代码更少(增加了新的语法Lambda表达式)
  • 强大的Stream API
  • 便于并行
  • 最大化减少空指针异常Optional

一、Lambda表达式

Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java语言表达能力得到了提升。

到底为什么用Lambda表达式呢?Lambda表达式有什么好?Lambda解决的是什么问题呢?我们先来看一下原来的匿名内部类:

原来的匿名内部类,在完成一个比较操作的时候需要写很多冗余代码,利用Lambda表达式来写,一行即可。

1、Lambda表达式基础语法:

Java8中引入了一个新的操作符 "->" 该操作符称为箭头操作符或 Lambda 操作符,箭头操作符将 Lambda 表达式拆分成两部分:

左侧:Lambda 表达式的参数列表;右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体

语法格式一:无参数,无返回值
    () -> System.out.println("Hello Lambda!");

语法格式二:有一个参数,并且无返回值
    (x) -> System.out.println(x)

语法格式三:若只有一个参数,小括号可以省略不写
    x -> System.out.println(x)

语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
    Comparator<Integer> com = (x, y) -> {
 	System.out.println("函数式接口");
 	return Integer.compare(x, y);
    };


语法格式五:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写
    Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
    (Integer x, Integer y) -> Integer.compare(x, y);
省略类型:(x, y) -> Integer.compare(x, y);

2、Lambda 表达式需要“函数式接口”的支持

函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。可以使用注解 @FunctionalInterface 修饰,作用:可以检查是否是函数式接口

二、函数式接口:Java8 内置的四大核心函数式接口

/*
 * Java8 内置的四大核心函数式接口
 * 
 * Consumer<T> : 消费型接口
 * 		void accept(T t);
 * 
 * Supplier<T> : 供给型接口
 * 		T get(); 
 * 
 * Function<T, R> : 函数型接口
 * 		R apply(T t);
 * 
 * Predicate<T> : 断言型接口
 * 		boolean test(T t);
 * 
 */
public class TestLambda {
	
	//Consumer<T> 消费型接口 :
	@Test
	public void test1(){
		happy(10000, (m) -> System.out.println("旅游花了" + m + "元"));
	} 
	
	public void happy(double money, Consumer<Double> con){
		con.accept(money);
	}
	
	//Supplier<T> 供给型接口 :
	@Test
	public void test2(){
		List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100));
		
		for (Integer num : numList) {
			System.out.println(num);
		}
	}
	
	//需求:产生指定个数的整数,并放入集合中
	public 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;
	}
	
	//Function<T, R> 函数型接口:
	@Test
	public void test3(){
		String newStr = strHandler("\t\t\t 你好,我是XXX   ", (str) -> str.trim());
		System.out.println(newStr);
		
		String subStr = strHandler("你好,我是XXX", (str) -> str.substring(2, 5));
		System.out.println(subStr);
	}
	
	//需求:用于处理字符串
	public String strHandler(String str, Function<String, String> fun){
		return fun.apply(str);
	}
	
	//Predicate<T> 断言型接口:
	@Test
	public void test4(){
		List<String> list = Arrays.asList("Hello", "wyq", "Lambda", "www", "ok");
		List<String> strList = filterStr(list, (s) -> s.length() > 3);
		
		for (String str : strList) {
			System.out.println(str);
		}
	}
	
	//需求:将满足条件的字符串,放入集合中
	public List<String> filterStr(List<String> list, Predicate<String> pre){
		List<String> strList = new ArrayList<>();
		
		for (String str : list) {
			if(pre.test(str)){
				strList.add(str);
			}
		}
		
		return strList;
	}
	
}

三、方法引用与构造器引用

1、方法引用:若 Lambda 体中的功能,已经有方法提供了实现,可以使用方法引用(可以将方法引用理解为 Lambda 表达式的另外一种表现形式)

  • 对象的引用 :: 实例方法名
  •  类名 :: 静态方法名
  • 类名 :: 实例方法名

注意:

①方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致!

这里println()这个方法已经有了实现,我们直接引用实现的方法即可,就可以写成 :对象的引用 :: 实例方法名。

方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致。

②若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName

2、构造器引用 :构造器的参数列表,需要与函数式接口中参数列表保持一致!

  • 类名 :: new

3、数组引用

  • 类型[] :: new
public class TestMethodRef {
	//对象的引用 :: 实例方法名
	@Test
	public void test1(){
		PrintStream ps = System.out;
		Consumer<String> con = (str) -> ps.println(str);
		con.accept("Hello World!");
		
		System.out.println("--------------------------------");
		
		Consumer<String> con2 = ps::println;
		con2.accept("Hello Java8!");
		
		Consumer<String> con3 = System.out::println;
	}
	
	//类名 :: 静态方法名
	@Test
	public void test2(){
		Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
		
		System.out.println("-------------------------------------");
		
		Comparator<Integer> com2 = Integer::compare;
	}
	
	
	//类名 :: 实例方法名
	@Test
	public void test3(){
		BiFunction<Double, Double, Double> fun = (x, y) -> Math.max(x, y);
		System.out.println(fun.apply(1.5, 22.2));
		
		System.out.println("--------------------------------------------------");
		
		BiFunction<Double, Double, Double> fun2 = Math::max;
		System.out.println(fun2.apply(1.2, 1.5));
	}
	
	//类名 :: 实例方法名
	@Test
	public void test4(){
		BiPredicate<String, String> bp = (x, y) -> x.equals(y);
		System.out.println(bp.test("abcde", "abcde"));
		
		System.out.println("-----------------------------------------");
		
		BiPredicate<String, String> bp2 = String::equals;
		System.out.println(bp2.test("abc", "abc"));
	}
	
	//构造器引用
	@Test
	public void test5(){
		Supplier<Employee> sup = () -> new Employee();
		System.out.println(sup.get());
		
		System.out.println("------------------------------------");
		
		Supplier<Employee> sup2 = Employee::new;  //调用无参构造器
		System.out.println(sup2.get());
		
		Function<String, Employee> fun = Employee::new;  //调用一个参数的构造器
		
		BiFunction<String, Integer, Employee> fun2 = Employee::new;  //调用两个参数的构造器
	}
	
	//数组引用
	@Test
	public void test6(){
		Function<Integer, String[]> fun = (args) -> new String[args];
		String[] strs = fun.apply(10);
		System.out.println(strs.length);
		
		System.out.println("--------------------------");
		
		Function<Integer, Employee[]> fun2 = Employee[] :: new;
		Employee[] emps = fun2.apply(20);
		System.out.println(emps.length);
	}
}

四、Stream API

什么是Stream?是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,流讲的是计算!”

注意:

  • ①Stream 自己不会存储元素;
  • ②Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream;
  • ③Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
/*
 * Stream API 的操作步骤:
 * 
 * 1. 创建 Stream
 * 		一个数据源(如:集合、数组),获取一个流
 * 2. 中间操作
 * 		一个中间操作链,对数据源的数据进行处理
 * 3. 终止操作(终端操作)
 * 		一个终止操作,执行中间操作链,并产生结果
 */
public class TestStreamAPI {
	
	//1. 创建 Stream
	@Test
	public void test1(){
		//1. Collection 提供了两个方法  stream() 与 parallelStream()
		List<String> list = new ArrayList<>();
		Stream<String> stream = list.stream(); //获取一个顺序流
		Stream<String> parallelStream = list.parallelStream(); //获取一个并行流
		
		//2. 通过 Arrays 中的 stream() 获取一个数组流
		Integer[] nums = new Integer[10];
		Stream<Integer> stream1 = Arrays.stream(nums);
		
		//3. 通过 Stream 类中静态方法 of()
		Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6);
		
		//4. 创建无限流
		//迭代
		Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2).limit(10);
		stream3.forEach(System.out::println);
		
		//生成
		Stream<Double> stream4 = Stream.generate(Math::random).limit(2);
		stream4.forEach(System.out::println);
		
	}
	
	//2. 中间操作
	List<Employee> emps = Arrays.asList(
			new Employee(102, "李四", 59, 6666.66, Status.BUSY),
			new Employee(101, "张三", 18, 9999.99, Status.FREE),
			new Employee(103, "王五", 28, 3333.33, Status.VOCATION),
			new Employee(104, "赵六", 8, 7777.77, Status.BUSY),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(105, "田七", 38, 5555.55, Status.BUSY)
	);
	
	/*
	映射
	map——接收 Lambda , 将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
	flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
	*/
	@Test
	public void test21(){
		Stream<String> str = emps.stream()
			.map((e) -> e.getName());
		
		System.out.println("-------------------------------------------");
		
		List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
		
		Stream<String> stream = strList.stream()
			   .map(String::toUpperCase);
		
		stream.forEach(System.out::println);
		
		Stream<Stream<Character>> stream2 = strList.stream()
			   .map(TestStreamAPI::filterCharacter);
		
		stream2.forEach((sm) -> {
			sm.forEach(System.out::println);
		});
		
		System.out.println("---------------------------------------------");
		
		Stream<Character> stream3 = strList.stream()
			   .flatMap(TestStreamAPI::filterCharacter);
		
		stream3.forEach(System.out::println);
	}
	
	public static Stream<Character> filterCharacter(String str){
		List<Character> list = new ArrayList<>();
		
		for (Character ch : str.toCharArray()) {
			list.add(ch);
		}
		
		return list.stream();
	}
	
	/*
		sorted()——自然排序
		sorted(Comparator com)——定制排序
	 */
	@Test
	public void test22(){
		emps.stream()
			.map(Employee::getName)
			.sorted()
			.forEach(System.out::println);
		
		System.out.println("------------------------------------");
		
		emps.stream()
			.sorted((x, y) -> {
				if(x.getAge() == y.getAge()){
					return x.getName().compareTo(y.getName());
				}else{
					return Integer.compare(x.getAge(), y.getAge());
				}
			}).forEach(System.out::println);
	}
	
	/*
	  筛选与切片
		filter——接收 Lambda , 从流中排除某些元素。
		limit——截断流,使其元素不超过给定数量。
		skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
		distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
	 */
	
	//内部迭代:迭代操作 Stream API 内部完成
	@Test
	public void test23(){
		//所有的中间操作不会做任何的处理
		Stream<Employee> stream = emps.stream()
			.filter((e) -> {
				System.out.println("测试中间操作");
				return e.getAge() <= 35;
			});
		
		//只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”
		stream.forEach(System.out::println);
	}
	
	//外部迭代
	@Test
	public void test24(){
		Iterator<Employee> it = emps.iterator();
		
		while(it.hasNext()){
			System.out.println(it.next());
		}
	}
	
	@Test
	public void test25(){
		emps.stream()
			.filter((e) -> {
				System.out.println("短路!"); // &&  ||
				return e.getSalary() >= 5000;
			}).limit(3)
			.forEach(System.out::println);
	}
	
	@Test
	public void test26(){
		emps.parallelStream()
			.filter((e) -> e.getSalary() >= 5000)
			.skip(2)
			.forEach(System.out::println);
	}
	
	@Test
	public void test27(){
		emps.stream()
			.distinct()
			.forEach(System.out::println);
	}
	
	//3.Stream 的终止操作:查找与匹配、规约、收集
	/*  查找与匹配
		allMatch——检查是否匹配所有元素
		anyMatch——检查是否至少匹配一个元素
		noneMatch——检查是否没有匹配的元素
		findFirst——返回第一个元素
		findAny——返回当前流中的任意元素
		count——返回流中元素的总个数
		max——返回流中最大值
		min——返回流中最小值
		forEach——内部迭代
	 */

	@Test
	public void test28(){
			boolean bl = emps.stream()
				.allMatch((e) -> e.getStatus().equals(Status.BUSY));
			
			System.out.println(bl);
			
			boolean bl1 = emps.stream()
				.anyMatch((e) -> e.getStatus().equals(Status.BUSY));
			
			System.out.println(bl1);
			
			boolean bl2 = emps.stream()
				.noneMatch((e) -> e.getStatus().equals(Status.BUSY));
			
			System.out.println(bl2);
	}
	
	@Test
	public void test29(){
		Optional<Employee> op = emps.stream()
			.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
			.findFirst();
		
		System.out.println(op.get());
		
		System.out.println("--------------------------------");
		
		Optional<Employee> op2 = emps.parallelStream()
			.filter((e) -> e.getStatus().equals(Status.FREE))
			.findAny();
		
		System.out.println(op2.get());
	}
	
	@Test
	public void test30(){
		long count = emps.stream()
						 .filter((e) -> e.getStatus().equals(Status.FREE))
						 .count();
		
		System.out.println(count);
		
		Optional<Double> op = emps.stream()
			.map(Employee::getSalary)
			.max(Double::compare);
		
		System.out.println(op.get());
		
		Optional<Employee> op2 = emps.stream()
			.min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
		
		System.out.println(op2.get());
	}
	
	//注意:流进行了终止操作后,不能再次使用
	@Test
	public void test34(){
		Stream<Employee> stream = emps.stream()
		 .filter((e) -> e.getStatus().equals(Status.FREE));
		
		long count = stream.count();
		
		stream.map(Employee::getSalary)
			.max(Double::compare);
	}
	
	/*
	归约
	reduce(T identity, BinaryOperator) / reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。
	*/
	@Test
	public void test35() {
		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);
		
		System.out.println("-------------------------");
		
		Optional<Double> op = emps.stream()
				.map(Employee :: getSalary)
				.reduce(Double :: sum);
		
		System.out.println(op.get());
	}
	
	//搜索名字中 “六”出现的次数
	@Test
	public void test36() {
		Optional<Integer> sum = emps.stream()
				.map(Employee::getName)
				.flatMap(TestStreamAPI::filterCharacter)
				.map((ch) -> {
					if(ch.equals('六')) {
						return 1;
					} else {
						return 0;
					}
				}).reduce(Integer::sum);
		
		System.out.println(sum.get());
	}
	
	//collect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
	@Test
	public void test37(){
		List<String> list = emps.stream()
			.map(Employee::getName)
			.collect(Collectors.toList());
		
		list.forEach(System.out::println);
		
		System.out.println("----------------------------------");
		
		Set<String> set = emps.stream()
			.map(Employee::getName)
			.collect(Collectors.toSet());
		
		set.forEach(System.out::println);

		System.out.println("----------------------------------");
		
		HashSet<String> hs = emps.stream()
			.map(Employee::getName)
			.collect(Collectors.toCollection(HashSet::new));
		
		hs.forEach(System.out::println);
	}
	
	@Test
	public void test38(){
		Optional<Double> max = emps.stream()
			.map(Employee::getSalary)
			.collect(Collectors.maxBy(Double::compare));
		
		System.out.println(max.get());
		
		Optional<Employee> op = emps.stream()
			.collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
		
		System.out.println(op.get());
		
		Double sum = emps.stream()
			.collect(Collectors.summingDouble(Employee::getSalary));
		
		System.out.println(sum);
		
		Double avg = emps.stream()
			.collect(Collectors.averagingDouble(Employee::getSalary));
		
		System.out.println(avg);
		
		Long count = emps.stream()
			.collect(Collectors.counting());
		
		System.out.println(count);
		
		System.out.println("--------------------------------------------");
		
		DoubleSummaryStatistics dss = emps.stream()
			.collect(Collectors.summarizingDouble(Employee::getSalary));
		
		System.out.println(dss.getMax());
	}
	
	//分组
	@Test
	public void test39(){
		Map<Status, List<Employee>> map = emps.stream()
			.collect(Collectors.groupingBy(Employee::getStatus));
		
		System.out.println(map);
	}
	
	//多级分组
	@Test
	public void test40(){
		Map<Status, Map<String, List<Employee>>> map = emps.stream()
			.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
				if(e.getAge() >= 60)
					return "老年";
				else if(e.getAge() >= 35)
					return "中年";
				else
					return "成年";
			})));
		
		System.out.println(map);
	}
	
	//分区
	@Test
	public void test41(){
		Map<Boolean, List<Employee>> map = emps.stream()
			.collect(Collectors.partitioningBy((e) -> e.getSalary() >= 5000));
		
		System.out.println(map);
	}
	
	@Test
	public void test42(){
		String str = emps.stream()
			.map(Employee::getName)
			.collect(Collectors.joining("," , "----", "----"));
		
		System.out.println(str);
	}
	
	@Test
	public void test43(){
		Optional<Double> sum = emps.stream()
			.map(Employee::getSalary)
			.collect(Collectors.reducing(Double::sum));
		
		System.out.println(sum.get());
	}
}

五、接口中的默认方法与静态方法

Java8 中允许接口中包含具有具体实现的方法,该方法称为“默认方法”,默认方法使用 default 关键字修饰。

例如:
interface MyFunc<T>{
    T func(int a);
    default String getName(){
        return "Hello Java8!";
    }
}

接口默认方法的“类优先”原则

若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时:

选择父类中的方法。如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。

接口冲突。如果一个父接口提供一个默认方法,另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突

public interface MyInterface1 {
	default String getName() {
		return "---MyInterface1---";
	}
}

public class FuClass {
	public String getName() {
		return "---FuClass---";
	}
}

public class SubClass extends FuClass implements MyInterface1{

}

public class MyMain {
	public static void main(String[] args) {
		System.out.println(new SubClass().getName());
	}
}

//运行结果:---FuClass---
public interface MyInterface1 {
	default String getName() {
		return "---MyInterface1---";
	}
}

public interface MyInterface2 {
	default String getName() {
		return "---MyInterface2---";
	}
}

public class TestDoubleInterface implements MyInterface1, MyInterface2{
	@Override
	public String getName() {
		return MyInterface1.super.getName();
		//return MyInterface2.super.getName();  选择一个进行实现
	}
}

接口中还可以有静态方法:

public interface MyInterface1 {
	default String getName() {
		return "---MyInterface1---";
	}
	
	public static void show() {
		System.out.println("接口中的静态方法");
	}
}

public class MyMain {
	public static void main(String[] args) {
		MyInterface1.show();
	}
}

//结果:接口中的静态方法

六、新时间日期API

使用LocalDate、LocalTime、LocalDateTime

LocalDate、LocalTime、LocalDateTime类的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、

日期和时间。他们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。

Instant时间戳

用于“时间戳”的运算。他是以Unix元年(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的描述进行运算。

Duration和Period

Duration:用于计算两个“时间”间隔

Period:用于计算两个“日期”间隔

日期的操纵

TemporalAdjuster:时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作。

TemporalAdjusters:该类通过静态方法提供了大量的常用TemporalAdjuster的实现。

例如获取下个周日:
LocalDate nextSunday = LocalDate.now().with(
    TemporalAdjusters.next(DayOfWeek.SUNDAY)
);

解析与格式化

java.time.format.DateTimeFormatter类:该类提供了三种格式化方法:预定义的格式标准;语言环境相关的格式;自定义的格式

时区的处理

Java8中加入了对时区的支持,带时区的时间分别为:ZonedDate、ZonedTime、ZonedDateTime,其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如:Asia/Shanghai等。ZoneId:该类中包含了所有的时区信息;getAvailableZoneIds():可以获取所有时区时区信息;of(id):用指定的时区信息获取ZoneId对象。

public class TestLocalDateTime {
	//1. LocalDate LocalTime LocalDateTime
	@Test
	public void test1() {
		LocalDateTime ldt = LocalDateTime.now();
		System.out.println(ldt);
		
		LocalDateTime ldt2 = LocalDateTime.of(2019, 1, 1, 1, 1, 1);
		System.out.println(ldt2);
		
		LocalDateTime ldt3 = ldt.plusYears(2);
		System.out.println(ldt3);
		
		LocalDateTime ldt4 = ldt.plusMonths(2);
		System.out.println(ldt4);
		
		System.out.println(ldt.getYear());
		System.out.println(ldt.getMonthValue());
		System.out.println(ldt.getDayOfMonth());
		System.out.println(ldt.getHour());
		System.out.println(ldt.getMinute());
		System.out.println(ldt.getSecond());
	}
	
	//2. Instant:时间戳(以 Unix 元年: 1970 年 1月 1日 00:00:00 到某个时间之间的毫秒值)
	@Test
	public void test2() {
		Instant ins1 = Instant.now(); // 默认获取的是 UTC 时区
		System.out.println(ins1);
		
		OffsetDateTime odt = ins1.atOffset(ZoneOffset.ofHours(8));
		System.out.println(odt);
		
		Instant ins2 = Instant.ofEpochSecond(60);
		System.out.println(ins2);
	}
	
	//3. Duration: 计算两个“时间”之间的间隔; Period : 计算两个“日期”之间的间隔
	@Test
	public void test3() {
		Instant ins1 = Instant.now();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		Instant ins2 = Instant.now();
		
		Duration duration = Duration.between(ins1, ins2);
		
		System.out.println(duration.toMillis());
		
		LocalDate ld1 = LocalDate.of(2020, 1, 1);
		LocalDate ld2 = LocalDate.now();
		Period period = Period.between(ld1, ld2);
		System.out.println(period);
	}
	
	//4. TemporalAdjuster: 时间矫正器
	@Test
	public void test4() {
		LocalDateTime ldt = LocalDateTime.now();
		System.out.println(ldt);
		
		LocalDateTime ldt2 = ldt.withDayOfMonth(10);
		System.out.println(ldt2);
		
		LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
		System.out.println(ldt3);
	}
	
	//5.DateTimeFormatter:格式化时间/日期
	@Test
	public void test5() {
		DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
		LocalDateTime ldt = LocalDateTime.now();
		
		String strDate = ldt.format(dtf);
		System.out.println(strDate);
		
		DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
		String strDate2 = dtf2.format(ldt);
		System.out.println(strDate2);
		
		LocalDateTime newDate = ldt.parse(strDate2, dtf2);
		System.out.println(newDate);
	}
}

七、Optional类

Optional<T> 类(java.util.Optional)是一个容器类,代表一个值存在或不存在,原来用null表示一个之不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。

/*  常用方法:
 *  Optional 容器类:用于尽量避免空指针异常
 * 	Optional.of(T t) : 创建一个 Optional 实例
 * 	Optional.empty() : 创建一个空的 Optional 实例
 * 	Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
 * 	isPresent() : 判断是否包含值
 * 	orElse(T t) :  如果调用对象包含值,返回该值,否则返回t
 * 	orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
 * 	map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
 * 	flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
 */
public class TestOptional {
	
	@Test
	public void test1() {
		//Optional<Employee> op = Optional.of(null);//java.lang.NullPointerException
		Optional<Employee> op = Optional.of(new Employee());
		Employee emp = op.get();
		System.out.println(emp);
	}
	
	@Test
	public void test2() {
		//创建了一个 空的 Optional 实例 op
		Optional<Employee> op = Optional.empty();
		System.out.println(op.get()); //java.util.NoSuchElementException: No value present
	}
	
	@Test
	public void test3() {
		Optional<Employee> op = Optional.ofNullable(null); 
//		Optional<Employee> op = Optional.ofNullable(new Employee());
//		if(op.isPresent()) {
//			System.out.println(op.get());
//		}
		
		Employee emp = op.orElse(new Employee(8,"张三", 18, 888.88, Status.FREE));
		System.out.println(emp);
	}
	
	@Test
	public void test4() {
		Optional<Employee> op = Optional.ofNullable(new Employee(8,"张三", 18, 888.88, Status.FREE));
//		Optional<String> str = op.map((e) -> e.getName());
//		System.out.println(str.get());
		
		Optional<String> str = op.flatMap((e) -> Optional.of(e.getName()));
		System.out.println(str.get());
	}
}

八、其他新特性

Java8 对注解处理提供了两点改进:可重复的注解及可用于类型的注解。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更这些源码资源,以适应各平台技术的最发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值