JDK1.8新特性
核心就是Lambda表达式和Stream Api
简介:1.速度更快
2.代码更少(新的表达式Lambda)
3.强大的StreamApi
4.便于并行
5.最大化减少空指针异常 (Optional)
1.Lambda 表达式
Lambda表达式是一个匿名函数 ,我们可以吧Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、灵活的代码。作为一种更紧凑的代码风格,让Java的语言表达能力得到了提升。
jdk1.8中 引入了新的操作符 -> 可以称作为箭头操作符 或者Lambda操作符
操作符 -> 把 Lambda表达式分成两部分 (参数列表)-> Lambda体
//排序的1.7写法 匿名内部类
Comparator<Integer> com =new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
/**
* 1.8 Lambda表达式
*/
Comparator<Integer> comparator=(x,y) -> Integer.compare(x, y);
public void function(Interface ...)
//调用function方法 使用 静态内部类
function(new Interface(){
@Override
.....
});
//调用function方法 使用 Lambda表达式
function( 重写的方法参数() -> 方法体 )
注意: 如果在Lambda中使用同级的属性 这个属性必须为final 虽然可以不写final,但是不能改变该变量的值,否则就会编译出错.
注意: 如果只有一个参数 小括号可以省略不写
注意: 如果Lambda体有多条语句 必须要加一对大括号
注意: Lambda方法形参的数据类型可以加 也 可以不加
2.函数式接口
注意:只有一个方法的接口叫做函数式接口,Lambda表达式需要函数式接口的支持 jdk中提供了 @FunctionalInterface 注解来检查是否是函数式接口
内置四大核心函数式接口
Consumer< T >: 消费型接口(只传参不返回) — 无返回值 方法体 void accept(T t);
Supplier< T > : 供给型接口(只返回) — 方法体 T get();
Function< T , R >:函数型接口(两个参数,传1返2):---- 方法体 R apply( T t);
Predicate< T >: 断言型接口 ----方法体 boolean test( T t);
其他内置函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
BiFunction<T,U,R> | T,U | R | 操作T,U返回R 包含的方法为 R apply(T t,U u); |
UnaryOperator | T | T | 传T返T |
BinaryOperator | T,T | T | 传两个T 返T |
BiConsumer<T,U> | T,U | void | 传T,U 无返回 |
ToIntFunction ToLongFunction ToDoubleFunction | T | int long double | 传T 返 Int / long / double |
IntFunction LongFunction DoubleFunction | Int long double | R | 传 Int / long / double ,返R |
3.方法引用与构造器引用
方法引用
方法引用: 若Lambda 体中的内容有方法已经实现了,我们可以使用“ 方法引”
(可以理解为Lambda的另一种表现形式)
注意:一定要是重写的方法要和方法体中调用的方法的参数和返回值相同(除非语法三)
主要有三种语法:
1) 语法一
对象名 :: 实例方法名
String t="方法引用";
Test test =System.out::print;
//Test test =System.out::print 相当于 Test test=s -> System.out.println(t) 前提是 重写的方法的参数和返回值要和调用的方法返回值相同 否则编译器会报错
// Test test=s -> System.out.println(t);
test.Test1(t);
2) 语法二
类名 :: 静态方法名
3) 语法三
类名 :: 实例方法名
构造器引用
格式 : ClassName :: new
注意: 使用构造器引用时,接口的方法参数和构造器的参数一定要对应
数组引用
语法: Type[ ] :: new
注意: 只能和Function接口配合使用
4.Stream API
Stream简介
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
Stream的操作
多个Stream中间流可以连接起来形成一条流水线,除非流水线上触发终止操作,否则中间操作不会被执行 任何的处理!而在终止操作时一次性全部处理,被成文惰性求值或者延迟加载 ;
一.创建Stream流
1.可以通过Collection 系列集合的 stream() 串行流 或 parallelStream() 并行流;
List<String> list=new ArrayList<String>();
Stream<String> stream = list.stream();
2.通过Arrays.stream() 方法获取数组流
Stream<Integer> stream2 = Arrays.stream(new Integer[] {1,2,3});
3.通过Stream的静态方法of()
Stream<String> of = Stream.of("a","b","c");
4.1.创建无限流-迭代
Stream<Integer> iterate = Stream.iterate(0,(x) -> x+2 );
iteaate.forEach(System.out::println);
//会产生无限个数 从0 开始 累计加2
//第二个参数类型为UnaryOperator<T> 传T返T
4.2.创建无限流-生成
Stream.generate(() -> Math.random());//无限生成随机小数
//参数类型为Supplier<T> 生产者
二. Stream的中间操作
1.筛选与切片
filter–>接受Lambda表达式,从流中排除某些元素
filter的方法定义 Predicate //断言型接口 传T 返回boolean
Stream<T> filter(Predicate<? super T> predicate);
limit–>截断流,使元素不超过给定量
Stream<T> limit(long maxSize);
skip–>跳过元素,返回一个扔掉了前n个元素的流,若流中元素小于n,则返回个空流
Stream<T> skip(long n);
distinct–>筛选 去重,通过流所生成的hashCode()和equals() 进行去重
Stream<T> distinct();
2.映射
map–>接受Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新元素
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
//传T 返R
flatMap–>接受一个函数作为参数,将流中的每个流 拆分组合成一个流
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
3.排序
排序: 自然排序:Comparable 定制排序 Comparator
List list=Arrays.asList(“aaa”,“bbb”,“ccc”);
//自然排序 使用的是Comparable
list.stream()
.sorted()
.forEach(System.out::println);
List<Pojo> list2=Arrays.asList(new Pojo("aaa",10),new Pojo("bbb",20));
//定制排序 使用的是Comparator
list2.stream()
.sorted((x1,x2) -> {
if (x1.getAge()==x2.getAge()) {
return x1.getName().compareTo(x2.getName());
}else {
return x1.getAge().compareTo(x2.getAge());
}
})
.forEach(System.out::println);
三.Stream的终止操作
1.查找和匹配
return boolean
allMatch–>检查是否匹配所有元素
anyMatch–>检查是否至少匹配一个元素
noneMatch–>检查是否没有匹配所有元素
return Optional
findFirst–>返回第一个元素
findAny–>返回当前流中的任意元素
return long
count–>返回流中的元素个数
return Optional
max–>返回流中的最大值
min–>返回流中的最小值
2.规约
reduce(T indentity,BinaryOperator)–>可以将流中的元素反复结合起来,得到一个值 类似于叠加 或者是 计数器
List<Integer> list=Arrays.asList(1,2,1,3);
Integer reduce = list.stream()
//jdk1.8提供的求和方法
.reduce(0, Integer::sum);
List<Pojo> list2=Arrays.asList(new Pojo("aaa",10),new Pojo("bbb",20));
Optional<Integer> reduce2 = list2.stream()
.map(Pojo::getAge)
.reduce(Integer::sum);
3.收集
collect–>将流转换为其他形式,接受一个Collector接口的实现,用于给Stream中元素做汇总得方法
List<Integer> collect = list2.stream()
.map(Pojo::getAge)
.collect(Collectors.toList());
//就是把重新转换成其他的元素 可以是集合 参数使用工具包Collectors里的静态方法 Collectors中的toCollection(List::new);方法比较强大 可以转换成任意集合,只需传入相应类的对象就行
四.并行流和串行流
**并行流**就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。 //底层使用Fork/Join框架实现
串行流就是流的处理任务是串行化的。
Java8中对并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API 可以声明性的通过parallel() 与sequential() 在并行流和顺序流中间进行切换。
parallel() 转换成并行流 sequential() 顺序流
5.接口中的默认方法与静态方法
Java1.8中提供了默认接口实现 就是在接口中除了全局静态常量和抽象方法外还有默认方法的实现 如果是静态方法也可以有方法体 声明如下
public interface MyInterface{
default void function(){
Syso("111");
}
static void functionStatic() {
System.out.println("111");
}
}
这样就会导致接口或父类之间的方法实现重复
若一个实现类的接口和父类中有重名的方法实现的话 默认类方法优先
若两个接口有相同的方法名称和参数列表的话,就强制需要实现类重写或者继承某个接口的方法: 接口名.super.方法
public interface Test {
default void function() {
System.out.println("111");
}
}
public interface Test2 {
default void function() {
System.out.println("111");
}
}
public class ClassImpl implements Test,Test2{
public void function(){
Test.super.function();
}
}
6.新时间日期API
java8提供了新的日期API,来取代之前的Date类。因为之前的日期API是1.0版本出的,大多数方法都已经过期,而且最重要的是Date日期类不是线程安全的。
新的日期API在java.time包下比如: LocalDate、LocalTime、LocalDateTime、Instant…
Duration用于时间的加减 between()
Zonedxxx为时区类
7.其他新特性
java8提供了重复注解和类型注解
//在jdk1.7中只能有一个注解 但是在1.8可以修饰多个
@MyAnnotation("aaa")
@MyAnnotation("aaa")
public void show(){
}
//但是该注解必须要使用@Repeatable(xxx.class) 注解 xxx也是 注解 定义如下:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotactions {
//必须是修饰注解的数组
MyAnnotation[] value();
}