Java8新特性

Java8的中文API网址: https://www.tbaqkj.com/javase/8/docs/api/

1. Java8新特性概要

  • 速度更快
  • 代码更少,Lambda表达式
  • 强大的Sream API
  • 便于并行
  • 最大化减少空指针异常                     

2. Lambda表达式基础语法

  • Java8中引入了一个新的操作符 "->"  该操作符称为箭头操作符或 Lambda 操作符;
  • 箭头操作符将 Lambda 表达式拆分成两部分;
  • 左侧为Lambda 表达式的参数列表;
  • 右侧为Lambda 表达式中所需执行的功能, 即 Lambda 体;
  • 若Lambda体中只有一条语句,则可以直接省略return和{ }
  • Lambda表达式的参数列表的数据类型可以省略,因JVM编译器通过上下文推断出数据类型,即“类型推断”

2.1 语法格式一:无参数,无返回值 

package com.isoftstone.test;
import org.junit.Test;

public class TestLambda_01 {
	@Test
	public void testJava(){
		new Thread(new Runnable() {
			@Override
			public void run() {
				//只有一条语句
				System.out.println(Thread.currentThread().getName());		
			}
		},"A").start();
	}
	
	@Test
	public void testJava8(){
		//只有一条语句
		new Thread(() -> System.out.println(Thread.currentThread().getName()),"A").start();
	}
	
	@Test
	public void testJava7_2(){
		new Thread(new Runnable() {
			@Override
			public void run() {
				//有多条语句
				System.out.println(Thread.currentThread().getName());		
				System.out.println(Thread.currentThread().getName());		
			}
		},"A").start();
	}
	
	@Test
	public void testJava8_2(){
		new Thread(() -> {
			//有多条语句
			System.out.println(Thread.currentThread().getName());
			System.out.println(Thread.currentThread().getName());
			},"A").start();
	}
}

2.2 语法格式二:只有一个参数,并且无返回值,此时参数小括号可写可不写

package com.isoftstone.test;
import java.util.function.Consumer;
import org.junit.Test;

public class TestLambda_02 {
	@Test
	public void testJava(){
		Consumer con = new Consumer() {
			//只有一个参数
			@Override
			public void accept(String t) {
				System.out.println(t);
			}
		};
		con.accept("我的地盘听我的!");
	}
	
	@Test
	public void testJava8(){
		//只有一个参数
		Consumer con = (x) -> System.out.println(x);
		con.accept("我的地盘听我的!");
		
		//只有一个参数
		//参数(x) 可以省略为 x
		Consumer con2 = x -> System.out.println(x);
		con2.accept("我的地盘听我的2222!");
		
		//只有一个参数
		//参数(x) 可加可不加类型,这里加String,默认推断这里也是String
		Consumer con3 = (String x) -> System.out.println(x);
		con3.accept("我的地盘听我的3333!");
		
	}
}

2.3 语法格式三:有两个或两个以上的参数,有返回值

package com.isoftstone.test;
import java.util.Comparator;
import org.junit.Test;

public class TestLambda_03 {
	@Test
	public void testJava(){
		Comparator com = new Comparator() {
			@Override
			public int compare(Integer x, Integer y) {
				System.out.println("函数式接口");
				return Integer.compare(x, y);
			}
		};
		int compare = com.compare(1, 2);
		System.out.println(compare);
		
		Comparator com2 = new Comparator() {
			@Override
			public int compare(Integer x, Integer y) {
				return Integer.compare(x, y);
			}
		};
		int compare2 = com2.compare(1, 2);
		System.out.println(compare2);
	}
	
	@Test
	public void testJava8(){
		Comparator com = (x,y) -> {
			System.out.println("函数式接口");
			return Integer.compare(x, y);
		};
		int compare = com.compare(1, 2);
		System.out.println(compare);

		Comparator com2 = (x,y) -> Integer.compare(x, y);
		int compare2 = com2.compare(1, 2);
		System.out.println(compare2);
	}
}

3. Lambda表达式需要“函数式接口”的支持

  • 只包含一个抽象方法的接口,称为 函数式接口。
  • 我们可以在任意函数式接口上使用 @ FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口;

3.1 举例 计算两个数

3.1.1 创建一个函数式接口,供两个数计算使用

package com.isoftstone.interfaces;

@FunctionalInterface
public interface MyCalculate {
	//@FunctionalInterface修饰的类,只能有一个抽象方法
	public double calculate(double a,double b);
}

3.1.2 测试,根据接口可以随意调整是加减乘除

package com.isoftstone.test;
import org.junit.Test;
import com.isoftstone.interfaces.MyCalculate;

public class TestLambda_04 {
	private double operation(double a, double b, MyCalculate myCalculate) {
		return myCalculate.calculate(a, b);
	}
	
	@Test
	public void testJava(){
		double value = operation(1.5,2.5,new MyCalculate(){
			@Override
			public double calculate(double a, double b) {
				return a + b;
			}});
		System.out.println(value);
		value = operation(9,3,new MyCalculate(){
			@Override
			public double calculate(double a, double b) {
				return a - b;
			}});
		System.out.println(value);
	}
	

	@Test
	public void testJava8(){
		double value = operation(1.5,2.5,(x,y) -> x + y);
		System.out.println(value);
		value = operation(9,3,(x,y) -> x - y);
		System.out.println(value);
	}
}

3.2 举例 处理字符串

3.2.1 创建一个函数式接口,供字符串处理使用

package com.isoftstone.interfaces;

@FunctionalInterface
public interface MyStringHandler {
	//@FunctionalInterface修饰的类,只能有一个抽象方法
	public String handler(String str);
}

3.2.2 测试,根据接口可以随意修改字符串的处理方式

package com.isoftstone.test;
import org.junit.Test;
import com.isoftstone.interfaces.MyStringHandler;

public class TestLambda_05 {
	private String strHandler(String str, MyStringHandler ms) {
		return ms.handler(str);
	}
	
	@Test
	public void testJava(){
		String trimStr = strHandler(" [My Name is ZMJ!] ", new MyStringHandler() {
			@Override
			public String handler(String str) {
				return str.trim();
			}
		});
		System.out.println("trimStr="+trimStr);
		String substring = strHandler(" [My Name is ZMJ!] ", new MyStringHandler() {
			@Override
			public String handler(String str) {
				return str.substring(2,5);
			}
		});
		System.out.println("substring="+substring);
	}
	

	@Test
	public void testJava8(){
		String trimStr = strHandler(" [My Name is ZMJ!] ", (x) -> x.trim());
		System.out.println("trimStr="+trimStr);
		String substring = strHandler(" [My Name is ZMJ!] ", (x) -> x.substring(2,5));
		System.out.println("substring="+substring);
	}
}

4. Java8内置四大核心函数式接口

其他的函数式接口详见  java.util.function.*

Java8新特性_第1张图片

package com.isoftstone.test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.junit.Test;

public class TestCoreInterface {
	//消费型接口 Consumer
	private void buy(double money,Consumer c) {
		c.accept(money);
	}
	
	//供给型接口 Supplier
	private List getNumList(int count,Supplier s) {
		List list = new ArrayList<>();
		for (int i = 0; i < count; i++) {
			list.add(s.get());
		}
		return list;
	}
	
	//函数型接口 Function
	private String strHandler(String str,Function f) {
		return f.apply(str);
	}
	
	//断言型接口 Predicate
	private List filterStr(List strList,Predicate p) {
		List list = new ArrayList<>();
		for (String str : strList) {
			if(p.test(str)) {
				list.add(str);
			}
		}
		return list;
	}
	
	@Test
	public void testJava(){
		//消费型接口 Consumer
		buy(10000, new Consumer(){
			@Override
			public void accept(Double t) {
				System.out.println("花费="+t);
			}
		});
		
		//供给型接口 Supplier
		List list = getNumList(5, new Supplier() {
			@Override
			public Integer get() {
				return (int) (Math.random()*100);
			}
		});
		for (Integer integer : list) {
			System.out.println(integer);
		}
		
		//函数型接口 Function
		String trimStr = strHandler(" Where there is a will there is a way! ", new Function() {
			@Override
			public String apply(String t) {
				return t.trim();
			}
		});
		System.out.println("trimStr="+trimStr);
		
		//断言型接口 Predicate
		List strList = Arrays.asList("Hello","World","!","I","Can","Do");
		List filterStrList = filterStr(strList, new Predicate() {
			@Override
			public boolean test(String t) {
				return t.length() > 4;
			}
		});
		for (String string : filterStrList) {
			System.out.println(string);
		}
	}
	
	@Test
	public void testJava8(){
		//消费型接口 Consumer
		buy(10000,(money) -> System.out.println("花费="+money));
		//供给型接口 Supplier
		List list = getNumList(5, () -> (int) (Math.random()*100));
		for (Integer integer : list) {
			System.out.println(integer);
		}

		//函数型接口 Function
		String trimStr = strHandler(" Where there is a will there is a way! ", (str) -> str.trim());
		System.out.println("trimStr="+trimStr);
		
		//断言型接口 Predicate
		List strList = Arrays.asList("Hello","World","!","I","Can","Do");
		List filterStrList = filterStr(strList, (str) -> str.length() > 4);
		for (String string : filterStrList) {
			System.out.println(string);
		}
	}
}

5. 引用

5.1 方法引用

  • 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用;
  • 实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致;
  • 使用操作符 “ ::” 将方法名和对象或类的名字分隔开来
package com.isoftstone.test;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.junit.Test;
import com.isoftstone.bean.Employee;

public class TestMethodReferences {
	@Test
	public void testJava8(){
		//改进前
		Consumer c1 = (str) -> System.out.println(str);
		c1.accept("c1");
		//改进后  对象::实例方法名
		Consumer c2 = System.out::println;
		c2.accept("c2");
		
		//改进前
		Employee emp = new Employee("张三",25,10000);
		Supplier s = () -> emp.getName();
		System.out.println(s.get());
		//改进后  对象::实例方法名
		Employee emp2 = new Employee("李四",25,10000);
		Supplier s2 = emp2::getName;
		System.out.println(s2.get());
		
		//改进前
		Comparator com = (x,y) -> Integer.compare(x, y);
		//改进后   类名::静态方法名
		Comparator com2 = Integer::compare;
		
		//改进前
		BiPredicate bp = (x,y) -> x.equals(y);
		//改进后  类名::实例方法名
		//只有在第一个参数是实例方法调用者且第二个参数是实例方法的参数时,才可以这么写
		BiPredicate bp2 = String::equals;
	}
}

5.2 构造器引用

  • 格式: 类名 :: new
  • 与函数式接口相结合,自动与函数式接口中方法兼容;
  • 可以把构造器引用赋值给定义的方法,与构造器参数;
  • 列表要与接口中抽象方法的参数列表一致
package com.isoftstone.test;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import org.junit.Test;
import com.isoftstone.bean.Employee;

public class TestConstructorReferences {
	@Test
	public void testJava8_1(){
		//改进前
		Supplier sup = () -> new Employee();
		
		//改进后 构造器引用     类名::new
		Supplier sup2 = Employee::new;
	}
	@Test
	public void testJava8_2(){
		//改进前
		Function fun = (x) -> new Employee(x);
		
		//改进后  构造器只要存在就会自动匹配
		Function fun2 = Employee::new;
		
		//如果匹配Employee的两个int的构造器
		BiFunction bf = Employee::new;
	}
}

5.3 数组引用

package com.isoftstone.test;
import java.util.function.Function;
import org.junit.Test;

public class TestArrayReferences {
	@Test
	public void testJava8(){
		//改进前
		Function fun = (x) -> new String[x];
		String[] strs = fun.apply(10);
		System.out.println(strs.length);
		
		//改进后
		Function fun2 = String[]::new;
		String[] strs2 = fun2.apply(10);
		System.out.println(strs2.length);
	}
}

6. Stream API

  • Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作;
  • Stream 自己不会存储元素,操作是延迟执行的;
  • Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream

6.1 创建流的方式

package com.isoftstone.test;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
import org.junit.Test;
import com.isoftstone.bean.Employee;
import com.isoftstone.bean.Employee.Status;

public class TestCreateStream {
	// 创建流  >> 中间操作   >> 终止操作
	@Test
	public void testJava8_create(){//创建Stream流的四种方式
		//方式一: 通过 Collection 系列集合提供的stream()或parallelStream()
		List empList = Arrays.asList(
				new Employee("张三",18,3333.5,Status.FREE),
				new Employee("李四",28,4444.5,Status.BUSY),
				new Employee("赵武",38,5555.5,Status.VOCATION),
				new Employee("王柳",68,6666.5,Status.FREE),
				new Employee("田七",78,7777.5,Status.BUSY)
		);
		Stream stream = empList.stream();
		
		//方式二:通过 Arrays 中的静态方法 stream()获取数组流
		Employee[] empArr = new Employee[2];
		empArr[0] = new Employee("WWW", 22, 5000, Status.BUSY); 
		empArr[1] = new Employee("MMM", 33, 6000, Status.FREE); 
		Stream stream2 = Arrays.stream(empArr);
		
		//方式三:通过Stream 类中的静态方法 of()
		Stream stream3 = Stream.of("aaa","bbb","ccc");
		
		//方式四:创建一个无限流
		Stream stream4 = Stream.iterate(0, (x) -> x+2);
		Stream stream5 = Stream.generate(() -> Math.random());
		
		//测试 输出结果
		System.out.println("------通过 Collection 系列集合提供的stream()或parallelStream()-----");
		stream.forEach(System.out::println);
		System.out.println("\n------通过 Arrays 中的静态方法 stream()获取数组流-----");
		stream2.forEach(System.out::println);
		System.out.println("\n------通过Stream 类中的静态方法 of()-----");
		stream3.forEach(System.out::println);
		System.out.println("\n------创建一个无限流 stream4-----");
		stream4.limit(3).forEach(System.out::println);
		System.out.println("\n------创建一个无限流 stream5-----");
		stream5.limit(3).forEach(System.out::println);
	}
}

6.2  流的中间操作

package com.isoftstone.test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
import org.junit.Test;
import com.isoftstone.bean.Employee;
import com.isoftstone.bean.Employee.Status;

public class TestStreamMiddleOperate {
	// 创建流  >> 中间操作   >> 终止操作
	@Test
	public void testJava8_middle(){//中间操作,此时不会执行任何操作,相当于安排任务
		/*
		 * 操作1. 筛选与切片
		 * filter(Predicate p) 接收 Lambda ,从流中排除某些元素
		 * distinct()          筛选,通过流所生成元素的 hashCode()和 equals()去除重复元素
		 * limit(long maxSize) 截断流,使其元素不超过给定数量
		 * skip(long n)        跳过元素,返回一个扔掉了前 n个元素的流。若流中元素不足 n个,则返回一个空流。与 limit(n)互补
		 */
		Stream stream = empList.stream()
				.filter((e) -> e.getAge() > 35)
				.skip(1)
				.limit(3)
				.distinct();
		
		/*
		 * 操作2.映射
		 * map(Function f)                  接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
		 * mapToDouble(ToDoubleFunction f)  接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream
		 * mapToInt(ToIntFunction f)        接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream
		 * mapToLong(ToLongFunction f)      接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream
		 * flatMap(Function f)              接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
		 * map与flatMap区别   可以用add(list)与addAll(list)来对比理解,前面是一个整体加进来;后面的并不是把一个整体加过来,而是将这个整体切分成每一份加进来
		 */
		Stream stream21 = strList.stream().map((str) -> str.toUpperCase());
		Stream stream22 = empList.stream().map(Employee::getName);
		Stream> stream23 = strList.stream().map(TestStreamMiddleOperate::filterCharacter);
		Stream stream24 = strList.stream().flatMap(TestStreamMiddleOperate::filterCharacter);
		
		/*
		 * 操作3.排序
		 * sorted()                    产生一个新流,其中按自然顺序排序(Comparable)
		 * sorted(Comparator  comp)    产生一个新流,其中按比较器顺序排序(Comparator)
		 */
		Stream stream3 = empList.stream().sorted((e1,e2) -> {
			if (e1.getAge() != e2.getAge()) {
				return e1.getAge() - e2.getAge();
			} else {
				return e1.getName().compareTo(e2.getName());
			}
		});
		
		//测试结果
		System.out.println("----操作1. 筛选与切片-----");
		stream.forEach(System.out::println);
		System.out.println("\n----操作2.映射map_1-----");
		stream21.forEach(System.out::println);
		System.out.println("\n----操作2.映射map_2-----");
		stream22.forEach(System.out::println);
		System.out.println("\n----操作2.映射map_3-----");
		stream23.forEach((sm) -> {sm.forEach(System.out::println);});
		System.out.println("\n----操作2.映射flatMap-----");
		stream24.forEach(System.out::println);
		System.out.println("\n----操作3.排序-----");
		stream3.forEach(System.out::println);
	}
	
	List empList = Arrays.asList(
			new Employee("张三",18,3333.5,Status.FREE),
			new Employee("李四",28,4444.5,Status.BUSY),
			new Employee("赵武",38,5555.5,Status.VOCATION),
			new Employee("王柳",68,6666.5,Status.FREE),
			new Employee("田七",78,7777.5,Status.BUSY),
			new Employee("田七",78,7777.5,Status.BUSY)
	);
	List strList = Arrays.asList("aaa","bbb","ccc","ddd","eee");
	
	public static Stream filterCharacter(String str) {
		List list = new ArrayList<>();
		char[] charArray = str.toCharArray();
		for (Character character : charArray) {
			list.add(character);
		}
		return list.stream();
	}
}

6.3  流的终止操作

package com.isoftstone.test;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.junit.Test;
import com.isoftstone.bean.Employee;
import com.isoftstone.bean.Employee.Status;

public class TestStreamTerminationOperate {
	// 创建流  >> 中间操作   >> 终止操作
	@Test
	public void testJava8_over(){//终止操作,此时才会一次性执行全部操作,相当于执行任务
		/*
		 * 操作1.查找与匹配
		 * allMatch(Predicate p)    检查是否匹配所有元素
		 * anyMatch( (Predicate p)  检查是否至少匹配一个元素
		 * noneMatch(Predicate p)   检查是否没有匹配所有元素
		 * findFirst()              返回第一个元素
		 * findAny()                返回当前流中的任意元素
		 * count()                  返回流中元素总数
		 * max(Comparator c)        返回流中最大值
		 * min(Comparator c)        返回流中最小值
		 * forEach(Consumer c)      内部迭代
		 */
		boolean allMatch = empList.stream().allMatch((e) -> Status.BUSY.equals(e.getStatus()));
		System.out.println("是否所以的员工都在忙=" +allMatch);
		boolean anyMatch = empList.stream().anyMatch((e) -> Status.FREE.equals(e.getStatus()));
		System.out.println("是否至少一名员工空闲=" +anyMatch);
		Optional op = empList.stream().findFirst();
		System.out.println("第一个员工的信息 "+op.get());
		Optional op2 = empList.parallelStream()
				.filter((e) -> Status.FREE.equals(e.getStatus()))
				.findAny();
		System.out.println("通过并行流随机找到一个目前处于空闲的员工  "+op2.get());
		Optional op3 = empList.stream().map(Employee::getSalary).min(Double::compare);
		System.out.println("最低工资="+op3.get());
		
		/*
		 * 操作2.规约
		 * reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 T
		 * reduce(BinaryOperator b)  可以将流中元素反复结合起来,得到一个值。返回 Optional
		 */
		Integer sum = integerList.stream().reduce(0,(x,y) -> x +y);
		System.out.println("求和=" + sum);
		Optional optional = empList.stream().map(Employee::getSalary).reduce(Double::sum);
		System.out.println("求工资总和=" + optional.get());
		
		/*
		 * 操作3.收集
		 * collect(Collector c) 将流转换为其他形式
		 * 接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
		 * Collectors的静态方法:
		 *    toList          把流中元素收集到List
		 *    toList          把流中元素收集到List
		 *    toSet           把流中元素收集到Set
		 *    toCollection    把流中元素收集到创建的集合
		 *    partitioningBy  分区,满足条件的一部分,不满足条件的一部分
		 *    counting\averaging*\sum*\maxBy\groupingBy*\......
		 */
		empList.stream()
			.map(Employee::getName)
			.collect(Collectors.toList())
			.forEach(System.out::println);
		
		empList.stream()
			.map(Employee::getName)
			.collect(Collectors.toCollection(HashSet::new))
			.forEach(System.out::println);
		
		Optional maxSalaryOp = empList.stream().map(Employee::getSalary)
			.collect(Collectors.maxBy(Double::compare));
		System.out.println("最高工资=" + maxSalaryOp.get());
		
		Map> map = empList.stream()
				.collect(Collectors.partitioningBy((e) -> e.getSalary() > 4000));
		System.out.println(map);
	}
	List integerList = Arrays.asList(1,2,3,4,5,6,7,8,9);
	
	List empList = Arrays.asList(
			new Employee("张三",18,3333.5,Status.FREE),
			new Employee("李四",28,4444.5,Status.BUSY),
			new Employee("赵武",38,5555.5,Status.VOCATION),
			new Employee("王柳",68,6666.5,Status.FREE),
			new Employee("田七",78,7777.5,Status.BUSY)
	);
}

6.4  并行流与串行流

Stream API 可以声明性地通过 parallel() 与sequential() 在并行流与顺序流之间进行切换,默认是顺序流/串行流

package com.isoftstone.test;
import java.util.stream.LongStream;
import org.junit.Test;

public class TestParallelStream {
	@Test
	public void test(){
		long start = System.currentTimeMillis();
		long sum = 0L;
		for (long i = 0L; i <= 10000000000L; i++) {
			sum += i;
		}
		System.out.println(sum);
		long end = System.currentTimeMillis();
		System.out.println("耗费的时间为: " + (end - start)); //耗费的时间为: 12096-13533
	}
	
	@Test
	public void test2(){
		long start = System.currentTimeMillis();
		Long sum = LongStream.rangeClosed(0L, 10000000000L)
							 .parallel()
							 .sum();
		System.out.println(sum);
		long end = System.currentTimeMillis();
		System.out.println("耗费的时间为: " + (end - start)); //耗费的时间为: 9115-10477
	}
}

7.  Optional 类

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

package com.isoftstone.test;
import java.util.Optional;
import org.junit.Test;
import com.isoftstone.bean.Employee;
import com.isoftstone.bean.Employee.Status;

public class TestOptional {
	/*
	 常用方法:
		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
	 */
	@Test
	public void test() {
		Optional op = Optional.ofNullable(new Employee());
		if(op.isPresent()) {
			System.out.println("如果op有值,"+op.get());
		}
		//一般这里如果传过来的值是null时,会在这里就报空指针异常,快速锁定,而不像以前还要找是哪里发生了
		op = Optional.of(null);   System.out.println(op.get());
	}
	@Test
	public void test2() {
		Optional strOp = Optional
				.ofNullable(new Employee("zzz",22,345.5,Status.BUSY))
				.map((e) -> e.getName());
		System.out.println(strOp.get());
		strOp = Optional
				.ofNullable(new Employee("zzz",22,345.5,Status.BUSY))
				.flatMap((e) -> Optional.of(e.getName()));
		System.out.println(strOp.get());
	}
	@Test
	public void test3() {
		Optional op = Optional.ofNullable(null);
		//如果是null,则在使用这个方法orElse时,不会引起空指针,而是输出指定的默认值
		String name = getGodnessName(op);
		System.out.println(name);
	}
	public String getGodnessName(Optional man) {
		return man.orElse(new Man()).getGodnessOp().orElse(new Godness("苍老师")).getName();
	}
	class Man {
		private Optional godnessOp = Optional.empty();
		public Man() {
		}
		public Man(Optional godnessOp) {
			this.godnessOp = godnessOp;
		}
		public Optional getGodnessOp() {
			return godnessOp;
		}
		public void setGodnessOp(Optional godnessOp) {
			this.godnessOp = godnessOp;
		}
	}
	class Godness {
		private String name;
		public Godness(String name) {
			this.name = name;
		}
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
	}
}

8. 接口中的默认方法与静态方法

  • Java 8中允许接口中包含具有具体实现的方法,该方法称为“默认方法”,默认方法使用 default 关键字修饰
  • 接口默认方法的 ” 类优先 ” 原则。若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时选择父类中的方法。如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突
  • Java8 中,接口中允许添加静态方法

9. 新时间日期 API

9.1 解决传统日期格式化线程安全问题

package com.isoftstone.test;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.junit.Test;

public class TestSimpleDateFormat {
	@Test
	public void testJava8_DateTimeFormatter() {
		DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		Callable task = new Callable() {
			@Override
			public LocalDate call() throws Exception {
				//新的日期格式化API可以解决线程安全问题
				return LocalDate.parse("2019-02-16",dtf);
			}
		};
		List> resultList = new ArrayList<>();
		ExecutorService pool = Executors.newFixedThreadPool(10);
		try {
			for (int i = 0; i < 10; i++) {
				resultList.add(pool.submit(task));
			}
			for (Future future : resultList) {
				System.out.println(future.get());
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		} finally {
			pool.shutdown();
		}
	}
	
	@Test
	public void testSimpleDateFormat() {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		Callable task = new Callable() {
			@Override
			public Date call() throws Exception {
				//传统的日期格式化API存在线程安全问题
				//return dateFormat.parse("2020-02-16");
				
				//还需要自己定义一个ThreadLocal才能解决线程安全问题
				return DateFormatThreadLocal.convert("2020-02-16");
			}
		};
		List> resultList = new ArrayList<>();
		ExecutorService pool = Executors.newFixedThreadPool(10);
		try {
			for (int i = 0; i < 10; i++) {
				resultList.add(pool.submit(task));
			}
			for (Future future : resultList) {
				System.out.println(future.get());
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		} finally {
			pool.shutdown();
		}
	}
}
class DateFormatThreadLocal {
	private static final ThreadLocal df = new ThreadLocal() {
		protected DateFormat initialValue() {
			return new SimpleDateFormat("yyyy-MM-dd");
		} 
	};
	public static Date convert(String source) throws ParseException {
		return df.get().parse(source);
	}
}

9.2 本地时间与时间戳

package com.isoftstone.test;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.time.ZoneOffset;
import org.junit.Test;

public class TestLocalDateTime {
	@Test
	public void test1() {
		System.out.println("当前系统日期时间="+LocalDateTime.now());//格式:2020-02-16T17:47:38.910
		
		LocalDate nowDate = LocalDate.now();
		System.out.println("当前系统日期="+nowDate);//格式:2020-02-16
		System.out.println(nowDate.getYear()+"-"+nowDate.getMonthValue()+"-"+nowDate.getDayOfMonth());//格式:2020-2-16
		System.out.println("相差="+Period.between(LocalDate.of(2019, 11, 1), nowDate));//格式:P3M15D
		
		LocalTime nowTime = LocalTime.now();
		System.out.println("当前系统时间="+nowTime);//格式:18:03:36.363
		System.out.println(nowTime.getHour()+":"+nowTime.getMinute()+":"+nowTime.getSecond());//格式:18:5:10
		
		LocalDateTime dt = LocalDateTime.of(2020, 02,16,17,24,33);
		System.out.println("拼接好的日期时间="+dt);//值:2020-02-16T17:24:33
		System.out.println("加上两年的结果="+ dt.plusYears(2));//值:2022-02-16T17:24:33
		System.out.println("减去两个月的结果="+ dt.minusMonths(2));//值:2019-12-16T17:24:33
		
		Instant instant = Instant.now();
		System.out.println("时间戳="+instant.toEpochMilli());
		System.out.println("北京时间="+ instant.atOffset(ZoneOffset.ofHours(8)));//格式:2020-02-16T18:10:42.884+08:00
		System.out.println("从1970年1月1日加上60秒="+Instant.ofEpochSecond(60));//格式:1970-01-01T00:01:00Z
		System.out.println("相差的毫秒数="+Duration.between(instant, Instant.now()).toMillis());
	}
}

9.3 时间校正器

  •  TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作
  • TemporalAdjusters : 该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现
package com.isoftstone.test;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import org.junit.Test;

public class TestTemporalAdjuster {
	@Test
	public void test() {
		LocalDateTime withDayOfMonth = LocalDateTime.now().withDayOfMonth(10);
		System.out.println("将当前日期的日改为10="+withDayOfMonth);
		LocalDate ldt = LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
		System.out.println("下个周日是哪天?"+ldt);//格式:2020-02-23
		
		LocalDate nextWorkDate = LocalDate.now().with((d) -> {
			LocalDate ld = (LocalDate)d;
			DayOfWeek dayOfWeek = (ld).getDayOfWeek();
			if (dayOfWeek.equals(DayOfWeek.FRIDAY)) {
				return ld.plusDays(3);
			} else if (dayOfWeek.equals(DayOfWeek.SATURDAY)) {
				return ld.plusDays(2);
			}
			return ld.plusDays(1);
		});
		System.out.println("下一个工作日是="+nextWorkDate);//格式:2020-02-17
	}
}

9.4 时间格式化与时区的处理

package com.isoftstone.test;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Set;
import org.junit.Test;

public class TestDateTimeFormatter {
	@Test
	public void test() {
		DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		System.out.println(dtf.format(LocalDateTime.now()));//格式:2020-02-16 23:09:53
		
		LocalDateTime parse = LocalDateTime.now().parse("2020-02-16 23:09:53",dtf);
		System.out.println(parse);//格式:2020-02-16T23:09:53
		
		Set zoneIds = ZoneId.getAvailableZoneIds();
		System.out.println("------所有的时区----");
		zoneIds.forEach(System.out::println);
		
		LocalDateTime hongKongDateTime = LocalDateTime.now(ZoneId.of("Asia/Hong_Kong"));
		System.out.println("香港日期时间="+hongKongDateTime);//格式:2020-02-16T23:30:03.194
		
		ZonedDateTime beijingDateTime = LocalDateTime.now(ZoneId.of("Asia/Shanghai")).atZone(ZoneId.of("Asia/Shanghai"));
		System.out.println(beijingDateTime);//格式:2020-02-16T23:30:03.194+08:00[Asia/Shanghai]
	}
}

10. 重复注解与类型注解

package com.isoftstone.test;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.ElementType.TYPE_PARAMETER;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import org.junit.Test;

public class TestAnnotation {
	@Test
	public void test() {
		Class clazz = TestAnnotation.class;
		Method showMethod = null;
		try {
			showMethod = clazz.getMethod("show");
			MyAnnotation[] myAnnotations = showMethod.getAnnotationsByType(MyAnnotation.class);
			for (MyAnnotation myAnnotation : myAnnotations) {
				//会打印注解的值 Spring  SpringMVC
				System.out.println(myAnnotation.value());
			}
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
		
	}
	
	@MyAnnotation("Spring")
	@MyAnnotation("SpringMVC")
	public void show(@MyAnnotation("my") String str) {
	}
}

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotations{
	MyAnnotation[] value();
}

//@Repeatable 支持重复注解
@Repeatable(MyAnnotations.class)
//TYPE_PARAMETER  类型注解,注解到方法的参数上
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
	String value() default "abc";
}

代码获取网址:   https://github.com/zmjjobs/Java8.git

你可能感兴趣的:(Java基础)