jdk1.8新特性
Lambda表达式
lambda表达式本质上是一段匿名内部类,也可以是一段可以传递的代码,其优点有以下几点:
1.简洁代码:使繁杂的代码简洁化,极大减少代码量
其缺点也有:
1.读起来不方便
函数式接口
函数式接口的提出是为了给lambda表达式的使用提供更好的支持。
什么是函数式接口?
函数式接口就是只定义了一个抽象方法的接口(Object类的public方法除外),并且还提供了注解:@FunctionalInterface
常见的四大函数式接口:
1.Consumer< T > :消费型接口,有参无返回值
-
Supplier< T >:供给型接口,无参有返回值
-
Function< T >:函数式接口,有参有返回值
-
Predicate< T >:断言型接口,有参有返回值,返回值是boolean类型
方法引用和构造器调用
方法引用有三种表现形式:
1.对象::实列方法名
2.类::静态方法名
3.类::实列方法名
构造器引用:ClassName::new
数组引用:Type[]::new
Stream API
内置许多API可以有效的链式编程,让代码简洁
1.创建stream
1.校验通过Collection 系列集合提供的stream()或者paralleStream():list.stream(); 2.通过Arays的静态方法stream()获取数组流:Arrays.stream(数组) 3.通过Stream类中的静态方法of:Stream.of("ss","dd") 4.创建无限流--迭代:Stream.iterate(0,(x)->x+2) 0:从多少开始 x:参数名 x+2:按照什么方式迭代
2.中间操作
1.筛选:filter 过滤:limit 去重:distinct 遍历:forEach 2.生成新的流 通过map映射:emps.stream.map((e)->e.getAge()).forEach(System.out.println); 3.自然排序:emps.stream.sorted(e1,e2) ->{排序规则,利用compareTo进行排序}
3.终止操作
1.allMatch :检查是否匹配所有元素 2.anyMatch :检查是否至少匹配一个元素 3.noneMatch:检查是否没有匹配所有元素 4.findFirst:返回第一个元素 5.findAny:返回当前流中的任意元素 6.count:返回流中元素的总个数 7.max:返回流中最大值 8.min:返回流中最小值 9.reduce:可以将流中元素反复结合起来,得到一个值 10.Collect:将流转换为其他形式,接收一个Collection接口的实现,用于给Stream中元素做汇总的方法
/**
* 查找和匹配
* allMatch-检查是否匹配所有元素
* anyMatch-检查是否至少匹配一个元素
* noneMatch-检查是否没有匹配所有元素
* findFirst-返回第一个元素
* findAny-返回当前流中的任意元素
* count-返回流中元素的总个数
* max-返回流中最大值
* min-返回流中最小值
*/
/**
* 检查是否匹配元素
*/
boolean b1 = emps.stream()
.allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b1);
boolean b2 = emps.stream()
.anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b2);
boolean b3 = emps.stream()
.noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b3);
Optional<Employee> opt = emps.stream()
.findFirst();
System.out.println(opt.get());
// 并行流
Optional<Employee> opt2 = emps.parallelStream()
.findAny();
System.out.println(opt2.get());
long count = emps.stream()
.count();
System.out.println(count);
Optional<Employee> max = emps.stream()
.max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(max.get());
Optional<Employee> min = emps.stream()
.min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(min.get());
/**
* reduce :规约操作
*/
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer count2 = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(count2);
Optional<Double> sum = emps.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(sum);
/**
* collect:收集操作
*/
List<Integer> ageList = emps.stream()
.map(Employee::getAge)
.collect(Collectors.toList());
ageList.stream().forEach(System.out::println);
并行流和串行流 在jdk1.8新的stream包中针对集合的操作也提供了并行操作流和串行操作流。并行流就是把内容切割成多个数据块,并且使用多个线程分别处理每个数据块的内容。Stream api中声明可以通过parallel()与sequential()方法在并行流和串行流之间进行切换。 jdk1.8并行流使用的是fork/join框架进行并行操作
ForkJoin框架 Fork/Join 框架:就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行 join 汇总。 关键字:递归分合、分而治之。 采用 “工作窃取”模式(work-stealing): 当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线 程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中 相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的 处理方式上.在一般的线程池中,如果一个线程正在执行的任务由于某些原因 无法继续运行,那么该线程会处于等待状态.而在fork/join框架实现中,如果 某个子问题由于等待另外一个子问题的完成而无法继续运行.那么处理该子 问题的线程会主动寻找其他尚未运行的子问题来执行.这种方式减少了线程 的等待时间,提高了性能.。
/**
* 要想使用Fark—Join,类必须继承
* RecursiveAction(无返回值)
* Or
* RecursiveTask(有返回值)
*
*/
public class ForkJoin extends RecursiveTask<Long> {
/**
* 要想使用Fark—Join,类必须继承RecursiveAction(无返回值) 或者
* RecursiveTask(有返回值)
*
* @author Wuyouxin
*/
private static final long serialVersionUID = 23423422L;
private long start;
private long end;
public ForkJoin() {
}
public ForkJoin(long start, long end) {
this.start = start;
this.end = end;
}
// 定义阙值
private static final long THRESHOLD = 10000L;
@Override
protected Long compute() {
if (end - start <= THRESHOLD) {
long sum = 0;
for (long i = start; i < end; i++) {
sum += i;
}
return sum;
} else {
long middle = (end - start) / 2;
ForkJoin left = new ForkJoin(start, middle);
//拆分子任务,压入线程队列
left.fork();
ForkJoin right = new ForkJoin(middle + 1, end);
right.fork();
//合并并返回
return left.join() + right.join();
}
}
/**
* 实现数的累加
*/
@Test
public void test1() {
//开始时间
Instant start = Instant.now();
//这里需要一个线程池的支持
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Long> task = new ForkJoin(0L, 10000000000L);
// 没有返回值 pool.execute();
// 有返回值
long sum = pool.invoke(task);
//结束时间
Instant end = Instant.now();
System.out.println(Duration.between(start, end).getSeconds());
}
/**
* java8 并行流 parallel()
*/
@Test
public void test2() {
//开始时间
Instant start = Instant.now();
// 并行流计算 累加求和
LongStream.rangeClosed(0, 10000000000L).parallel()
.reduce(0, Long :: sum);
//结束时间
Instant end = Instant.now();
System.out.println(Duration.between(start, end).getSeconds());
}
@Test
public void test3(){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.stream().forEach(System.out::print);
list.parallelStream()
.forEach(System.out::print);
}
//多线程展示
@Test
public void test(){
// 并行流 多个线程执行
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
numbers.parallelStream()
.forEach(System.out::print);
//
System.out.println("=========================");
numbers.stream()
.sequential()
.forEach(System.out::print);
}
Optional容器:使用Optional容器可以快速的定位NPE,并且在一定程度上可以减少对参数非空检验的代码量
/**
* 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
*
* 总结:Optional.of(null) 会直接报NPE
*/
Optional<Employee> op = Optional.of(new Employee("zhansan", 11, 12.32, Employee.Status.BUSY));
System.out.println(op.get());
// NPE
Optional<Employee> op2 = Optional.of(null);
System.out.println(op2);
@Test
public void test2(){
Optional<Object> op = Optional.empty();
System.out.println(op);
// No value present
System.out.println(op.get());
}
@Test
public void test3(){
Optional<Employee> op = Optional.ofNullable(new Employee("lisi", 33, 131.42, Employee.Status.FREE));
System.out.println(op.get());
Optional<Object> op2 = Optional.ofNullable(null);
System.out.println(op2);
// System.out.println(op2.get());
}
@Test
public void test5(){
Optional<Employee> op1 = Optional.ofNullable(new Employee("张三", 11, 11.33, Employee.Status.VOCATION));
System.out.println(op1.orElse(new Employee()));
System.out.println(op1.orElse(null));
}
@Test
public void test6(){
Optional<Employee> op1 = Optional.of(new Employee("田七", 11, 12.31, Employee.Status.BUSY));
op1 = Optional.empty();
Employee employee = op1.orElseGet(() -> new Employee());
System.out.println(employee);
}
@Test
public void test7(){
Optional<Employee> op1 = Optional.of(new Employee("田七", 11, 12.31, Employee.Status.BUSY));
System.out.println(op1.map( (e) -> e.getSalary()).get());
}
接口中的默认方法和静态方法
在接口中可以使用default和static关键字来修饰接口中定义的普通方法,注意如果方法与实现类的父类方法同名是优先继承父类的方法,即"类优先",如果实现两个同名方法的接口,必须手动声明默认实现哪个接口中的方法。
新时间日期API
新的日期API LocalDate | LocalTime | LocalDateTime 新的日期API都是不可变的,更使用于多线程的使用环境中
耦合:当资源包缺失,影响程序编译,解耦合就算可以解决这个问题,可以使除了该异常的其它功能可以正常运行,整个项目都可以编译通过