jdk1.8新特性
速度更快、代码更少(Lambda)、强大的StrreamAPI、便于并行、最大化减少空指针异常:Optional、Nashorn引擎,允许在JVM上运行JS应用
Lambda表达式
Lambda是一个匿名函数,我们可以吧Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升
//无参无返回值 不用Lambda表达式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(111);
}
}).start();
//用Lambda表达式
new Thread(()->{
System.out.println(111);
}).start();
// 一个参数没有返回值
Consumer<String> con = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con.accept("快来玩耍吧");
System.out.println("*****************************");
Consumer<String> con1 = (String s) -> { System.out.println(s); };
//类型推断 参数类型可以省略,一个参数小括号大括号可以省略,return 也可以不用写
Consumer<String> con2 = s -> { System.out.println(s); };
Consumer<String> con1 = s -> System.out.println(s);
左边:lambda形参列表的参数类型可以忽略(类型推断);如果lambda形参列表只有一个参数 ‘()’ 可以省略,
右边:lambda体应该使用一对{}包裹;如果只有一条执行语句(可能是return语句),可以省略{},return也可以省略
本质:作为函数式接口的实例
函数式(Functional)接口
如果一个接口中,只声明了一个抽象方法,此接口就是函数式接口
@FunctionalInterface
public interface MyFunction {
void method();
}
@FunctionalInterface表示此类是函数式接口,帮我们在编译器检查,不写方法和一个以上的方法会编译报错
之前匿名实现类表示的现在都可以用Lambda来写
java.util.function定义了丰富的函数式接口
四大核心函数式接口如下,其他函数式接口参加API文档
- Consumber
给一个T参数,无返回 消费型 - Supplier
返回T对象 供给型 - Function<T,R> 函数型
- Predicate
返回boolean 断定型
方法引用与构造器引用
当要传递给lambda体的操作,已经有实现的方法了,可以使用方法引用,本质上就是lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例。
使用格式: 类(或对象) :: 方法名
使用要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同
方法引用
1.对象::非静态方法
User user = new User();
user.setUserName("赵二狗");
user.setId(1L);
user.setPassWord("123456");
Supplier<String> sup = () -> user.getUserName();
System.out.println(sup.get());
System.out.println("******************");
// Supplier<String>中 T get()
// Uuser 中 String getName()
Supplier<String> sup1 = user :: getUserName;
System.out.println(sup1.get());
2.类::静态方法
//Comparator中的 int compare(T t1, T t2);
//Integer中的 int compare(T t1, T t2);
Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2);
System.out.println(com1.compare(12,21));
System.out.println("****************");
Comparator<Integer> com2 = Integer::compare;
System.out.println(com2.compare(12,3));
Function<Double,Long> function = new Function<Double, Long>() {
@Override
public Long apply(Double aDouble) {
return Math.round(aDouble);
}
};
Function<Double,Long> function1 = (d) -> {return Math.round(d);};
Function<Double,Long> function2 = d -> Math.round(d);
//Function long apply(double d)
//Math long round(double d)
Function<Double,Long> function3 = Math :: round;
System.out.println(function3.apply(25.6));
3.类::非静态方法
//Comparator 中 的 int comapre(T t1,T t2)
//String 中 的 int t1.compareTo(t2)
// 两个参数,t1作为调用者 t2作为参数 也可以作为方法引用
Comparator<String> com1 = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
};
Comparator<String> com2 = (s1,s2) -> s1.compareTo(s2);
Comparator<String> com3 = String :: compareTo;
BiPredicate<String,String> pre = new BiPredicate<String, String>() {
@Override
public boolean test(String s1, String s2) {
return s1.equals(s2);
}
};
//BiPredicate boolean test(t1,t2)
//String boolean t1.equals(t2)
BiPredicate<String,String> pre1 = (s1,s2) -> s1.equals(s2);
BiPredicate<String,String> pre2 = String :: equals;
Function<User,String> function = new Function<User, String>() {
@Override
public String apply(User user) {
return user.getUserName();
}
};
//Function R apply(T t);
//User String getName();
// 参数作为调用者 t.getName() 所以还可以用方法引用
Function<User,String> function1 = user -> user.getUserName();
Function<User,String> function2 = User :: getUserName;
//平时用到的Lists.transform()
List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9);
Lists.transform(list, new com.google.common.base.Function<Integer, String>() {
@Override
public String apply(@Nullable Integer integer) {
return String.valueOf(integer);
}
});
List<String> transform = Lists.transform(list, String::valueOf);
System.out.println(transform.toString());
构造器引用
和方法引用类似,函数式接口的抽象方法形参列表和构造器的形参列表一致。
抽象方法的返回值类型即为构造器所属的类的类型
Supplier<User> sup = new Supplier<User>() {
@Override
public User get() {
return new User();
}
};
//Supplier User get()
//User User 空参构造器
Supplier<User> sup1 = () -> new User();
Supplier<User> sup2 = User :: new;
Function<Integer,User> fun = new Function<Integer, User>() {
@Override
public User apply(Integer id) {
return new User(id);
}
};
//Function User apply(Integer id)
//User User User(Integer id) 参数为Integer的有参构造器
Function<Integer,User> fun1 = id -> new User(id);
Function<Integer,User> fun2 = User :: new;
//数组可以看成特殊的类,构造器引用 同样适用
Function<Integer,String[]> fun = new Function<Integer, String[]>() {
@Override
public String[] apply(Integer length) {
return new String[length];
}
};
Function<Integer,String[]> fun1 = length -> new String[length];
Function<Integer,String[]> fun2 = String[] ::new;
}
强大的Stream API
把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充。可以极大提供java开发效率,让程序员写出高效率、干净、简介的代码。
Stream是Java8中处理结合的关键抽象概念,他可以指定你希望对结合进行的操作,可以执行非常复杂的查找、过滤、和映射数据等操作。使用StreamAPI对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用StreamAPI来执行操作。简而言之,StreamAPI提供了一种高效且易于使用的处理数据的方式。
为何使用Stream API
实际开发中,项目种多数 数据源都来自于Mysql,Oracle等。但现在数据源可以更多了,有MongDB,Redis等。而这些NoSQL的数据就需要Java层面去处理。(eg:只要最近三个月的数据)
Stream和Collection集合的区别: Collection是一种静态的内存数据结构,而Stream是有关计算的 。前者主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。
到底是什么?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
集合讲的是数据,Stream主要做计算
注意:
三个步骤
- 创建Stream。
一个数据源(如集合,数组),获取一个源 - 中间操作
一个中间链,对数据源的数据进行处理 - 终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果,之后,不会再被使用
实例化
//1 通过集合
//default Stream<E> stream() 返回一个顺序流
Stream<Integer> stream = list.stream();
//default Stream<E> parallelStream() 返回一个并行流
Stream<Integer> parallelStream = list.parallelStream();
//2 通过数组
IntStream stream1 = Arrays.stream(new int[]{1, 2, 3, 4, 5});
//3 通过Stream本身 of()
Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5);
Stream<Object> build = Stream.builder().add(1).add(2).build();
//4 通过Stream 创建无限流
//迭代 public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
//遍历前十个偶数
Stream<Integer> iterate = Stream.iterate(0, t -> t + 2).limit(10);
iterate.forEach(System.out :: println);
//生成 造数据
//public static<T> Stream<T> generate(Supplier<T> s)
Stream.generate(Math :: random);
中间操作
- 筛选与筛片
//筛选与切片
//filter(Predicate p) 排除/过滤
Stream<Integer> stream = list.stream();
//查询大于2的元素
stream.filter(integer -> integer > 2)
.forEach(System.out :: println);
//limit(n)截断,使元素数量不能超过给定数量
Stream<Integer> stream1 = list.stream();
//前两条数据
stream1.limit(2).forEach(System.out :: println);
//skip(n) 截断 跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流
stream1.skip(3).forEach(System.out :: println);
//distinct() 筛选,通过流所生成元素的hashCode()和equals()去重
Stream<Integer> stream2 = list.stream();
stream2.distinct().forEach(System.out :: println);
- 映射
//map(Function f) 将元素转换成其他形式或提取信息,该函数会被应用到每个元素上
//小写转大写
Stream<String> stream = Arrays.asList("aa", "bb", "cc", "dd", "ee").stream();
stream.map(str -> str.toUpperCase()).forEach(System.out :: println);
//练习1 获取姓名长度大于3的用户姓名
List<User> list = new ArrayList<User>();
// list.stream().map(user -> user.getUserName()); 得到一个name流
list.stream().map(User :: getUserName)
.filter(name -> name.length() > 3)
.forEach(System.out :: println);
//flatMap(Function f) 将流中的每个值都换成另一个流,然后吧所有流连接成一个流
//map相当于 list.add(list) flatMap相当于 list.addAll(list)
==map相当于 list.add(list) flatMap相当于 list.addAll(list)==
- 排序
//排序
//sorted() 产生一个新流,其中按自然顺序排序
Stream<String> stream = Arrays.asList("gg", "ff", "zz", "cc", "aa","bb").stream();
stream.sorted().forEach(System.out :: println);
//sorted(Comparator com) 产生一个新流,其中按比较器顺序排序
Stream<String> stream1 = Arrays.asList("gg", "ff", "zz", "cc", "aa","bb").stream();
//自定义倒序排序
stream1.sorted(String::compareTo).forEach(System.out :: println);
//泛型如果是实体类 需要实现Comparable接口
- 终止操作
流进行过终止操作后不可再进行中间操作。
//终止操作
List<User> list = new ArrayList<>();
//收集 collect(Collector c) 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总 的方法
//Collector接口中方法的实现决定了如何对流执行收集器的操作(如收集到List、Set、Map)
//另外,Collectors 类提供了很多静态方法,可以方便的创建收集器实例
//查找工资大于1000玩的员工结果返回成一个List Set
final List<User> listResult = list.stream().filter(user -> user.getSalary() > 10000)
.collect(Collectors.toList());
final Set<User> setResult = list.stream().filter(user -> user.getSalary() > 1000)
.collect(Collectors.toSet());
Optional 类
主要为了解决空指针异常(借鉴Guava的做法 Optional)
Optional
Javadoc描述:这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
@Test
public void test8() {
//不能传null
Optional<Dog> dog = Optional.of(new Dog());
System.out.println(dog);
//可以为空
final Optional<Object> o = Optional.ofNullable(null);
System.out.println(o);
}
@Test
public void test9() {
Dog dog = new Dog();
dog.setName("二狗");
//空指针
// System.out.println(getCatName(dog));
//无空指针 校验
System.out.println(getCatName2(null));
}
public String getCatName(Dog dog) {
//存在空指针风险
return dog.getCat().getName();
}
public String getCantName1(Dog dog) {
if (dog != null) {
Cat cat = dog.getCat();
if (cat != null) {
return cat.getName();
}
}
return null;
}
//Optional
public String getCatName2(Dog dog) {
Optional<Dog> optional = Optional.ofNullable(dog);
//此时dog1 一定非空
Dog dog1 = optional.orElse(new Dog("二狗"));
Cat cat = dog1.getCat();
Optional<Cat> optional1 = Optional.ofNullable(cat);
//如果 optional1.get()为空 就拿到 new Cat("小白") 相当于一个备胎~
Cat cat1 = optional1.orElse(new Cat("小白"));
return cat1.getName();
}