java8新特性
Lambda表达式
为什么要用lambda表达式??
优化代码
没有lambda表达式之前
//添加数据
List<Employee> employeeList = Arrays.asList(
new Employee("张三",20,5555.55),
new Employee("李四",34,6666.55),
new Employee("王五",25,7777.55),
new Employee("法外狂徒",19,4444.55),
new Employee("法内狂徒",30,8888.55)
);
/**
* 需求,找出年龄大于30岁的员工
*/
@Test
public void test1(){
List<Employee> employeeList = findAge(this.employeeList);
for (Employee employee : employeeList) {
System.out.println(employee);
}
}
public List<Employee> findAge(List<Employee> employees){
ArrayList<Employee> list = new ArrayList<>();
for (Employee employee : employees) {
if(employee.getAge() >= 30){
list.add(employee);
}
}
return list;
}
优化方式一: 采用策略模式
//新写个方法
public List<Employee> findAge2(List<Employee> employees,PredicateEmpliyee predicateEmpliyee){
ArrayList<Employee> arrayList = new ArrayList<Employee>();
for (Employee employee : employees) {
if(predicateEmpliyee.test(employee)){
arrayList.add(employee);
}
}
return arrayList;
}
//优化1 采用策略模式 建一个接口
package com.hy.lambda;
public interface PredicateEmpliyee<T> {
public boolean test(Employee employees);
}
//编写接口的实现类
package com.hy.lambda;
public class FindEmployeeAge implements PredicateEmpliyee<Employee> {
@Override
public boolean test(Employee employees) {
return employees.getAge() >= 30;
}
}
//使用
// 将实现类传入到方法中去
@Test
public void test2(){
List<Employee> employeeList = findAge2(this.employeeList, new FindEmployeeAge());
for (Employee employee : employeeList) {
System.out.println(employee);
}
}
优化方式二: 采用匿名内部类
/**
* 方式二: 使用匿名内部类 策略模式 每次搜需要写一个实现类,太麻烦了
* 这样就不要每次都去写实现类了
*/
@Test
public void test3(){
List<Employee> employeeList = findAge2(this.employeeList, new PredicateEmpliyee() {
@Override
public boolean test(Employee employees) {
return employees.getAge() >= 30;
}
});
for (Employee employee : employeeList) {
System.out.println(employee);
}
}
优化方式三:采用lambda表达式
/**
* 方式三 lambda表达式
* 将前面的实现类的方式和匿名内部类的方式 直接采用lambda表达式去实现
*/
@Test
public void test4(){
List<Employee> employeeList = findAge2(this.employeeList, e -> e.getAge() >= 30);
employeeList.forEach(System.out::println);
}
方式四: 使用stream() API 一行代码解决
/**
* 方式四 stream API
*/
@Test
public void test5(){
this.employeeList.stream()
.filter(e -> e.getAge() >= 30)
.forEach(System.out::println);
}
java内置四大核心函数式接口
/**
* java中内置的四大函数式接口
*
* Consumer<T> : 消费型接口
* void accept(T t); 可以用于处理一些不需要返回值的需求
*
* Supplier<T> : 供给型接口
* T get(); 用于一些传递参数进来处理然后返回结果
*
* Function<T,R> : 函数型接口
* R apply(T t);
*
* Predicate<T> : 断言型接口
* boolean test(T t);
*
*
*/
例子
/**
* 消费型接口 Consumer
*/
public void happy(double money , Consumer<Double> consumer){
consumer.accept(money);
}
@Test
public void test1(){
happy(100.00,(m) -> {
System.err.println("本次共使用"+m);
});
}
/**
* 供给型接口 Supplier
*/
public List<Integer> genList(int num, Supplier<Integer> supplier){
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
Integer n = supplier.get();
list.add(n);
}
return list;
}
@Test
public void test2(){
List<Integer> genList = genList(5, () -> (int) (Math.random() * 100));
for (Integer integer : genList) {
System.out.println(integer);
}
}
/**
* 函数型接口 Function
*/
public String strHandler(String str, Function<String,String> function){
return function.apply(str);
}
@Test
public void test3(){
String strHandler = strHandler(" \t\t\t 啊哈哈哈哈哈", (e) -> e.trim());
System.out.println(strHandler);
}
/**
* 断言型接口 Predicate
*/
public List<String> filterStr(List<String> strList, Predicate<String> predicate){
List<String> list = new ArrayList<>();
for (String s : strList) {
if(predicate.test(s)){
list.add(s);
}
}
return list;
}
@Test
public void test4(){
List<String> list = Arrays.asList("supplier", "function", "consumer", "predicate");
System.err.println(filterStr(list, (e) -> e.length() > 8));
}
方法引用和构造器引用
-
在函数式接口中已经存在的方法可以使用方法引用
-
如果该函数式接口中存在与lambda体中同样类型参数和返回值的时候,就可以使用方法引用
方法引用
对象::实例方法名
//对象::实例方法名
@Test
public void test1(){
//使用lambda表达式表示
Consumer<String> con = (e) -> System.out.println(e);
//使用方法引用表示
Consumer<String> con2 = System.out::println;
con.accept("11111");
con2.accept("22222");
}
类::静态方法名
//类:静态方法名
@Test
public void test2(){
//compare方法和Comparator接口中的抽象方法的返回值和参数一致
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
com.compare(1,2);
Comparator<Integer> com2 = Integer::compareTo;
System.out.println(com2.compare(2, 2));
}
类::实例方法名
//类:实例方法名
@Test
public void test3(){
BiPredicate<String,String> bp = (str1,str2) -> str1.equals(str1);
BiPredicate<String,String> bp2 = String::equals;
System.err.println(bp2.test("wooow", "444"));
}
构造器引用
- 构造器引用匹配的是与函数式接口中抽象方法的返回值类型和参数列表相同的构造器
实例对象::new
//构造器引用
@Test
public void test4(){
Supplier<Employee> con = () -> new Employee();
//在lambda表达式中的构造器引用 返回的是与函数式接口相匹配的构造器
Supplier<Employee> con2 = Employee::new;
System.out.println(con2.get());
}
强大的Stream流
-
流(Stream)到底是什么?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
注意
- Stream自己不会存储元素
- Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。
- Stream操作是延迟的,这意味这他们会等到需要结果的时候才执行。
Stream创建的四种方式
//Stream创建的四种方式
@Test
public void test1(){
//第一种方式 使用Collection系列的集合提供的stream()(串行)或parallelStream(并行)进行创建
List<Integer> arrayList = new ArrayList<Integer>();
arrayList.stream();
//第二种方式 通过Arrays中的stream()静态方法进行创建
Employee[] employeeList = new Employee[10];
Arrays.stream(employeeList);
//第三种方式 通过Stream类中的静态方法of
Stream.of("aa","bb","cc");
//第四种方式 创建无限流 使用迭代器创建无限流
Stream.iterate(0,(a) -> a+2).limit(10).forEach(System.out::println);
Stream.generate(() -> Math.random()).limit(10).forEach(System.out::println);
}
使用stream进行筛选与切片
/**
* 使用stream进行筛选与切片
* filter(Predicate pd) 排除某些元素,过滤
* distinct 筛选去除重复元素
* limit 截断流 获取流中给定个数
* skip 截取掉 与limit相反
*/
@Test
public void test1() {
//filter(Predicate pd) 排除某些元素,过滤
employeeList.stream()
.filter(e -> e.getAge() > 21)
.forEach(System.out::println);
System.out.println("---------------------------");
//distinct 筛选去除重复元素
employeeList.stream()
.distinct()
.forEach(System.out::println);
System.out.println("---------------------");
//limit 截断流 获取流中给定个数
employeeList.stream()
.limit(2)
.forEach(System.out::println);
System.out.println("---------------------");
//limit 截断流 获取流中给定个数 截取掉 与limit相反
employeeList.stream()
.skip(2)
.forEach(System.out::println);
}
映射
/**
* 映射
* map 接收一个函数参数,该函数会被应用到每个元素上 将每个元素映射成一个新的元素
* mapToDouble 可以将每个元素都转换成double类型
*/
@Test
public void test2(){
//map 接收一个函数参数,该函数会被应用到每个元素上 将每个元素映射成一个新的元素
employeeList.stream()
.map(Employee::getName)
.forEach(System.out::println);
System.out.println("---------------------");
// mapToDouble 可以将每个元素都转换成double类型
employeeList.stream()
.mapToDouble(Employee::getAge)
.forEach(System.out::println);
System.out.println("---------------------");
//mapToInt 可以将每个元素都转换成int类型
employeeList.stream()
.mapToInt(e -> (int) e.getSalary())
.forEach(System.out::println);
}
查找与匹配
/**
* 查找与匹配
* allMatch 检查是否匹配所有元素
*/
@Test
public void test3(){
//allMatch 检查是否匹配所有元素
boolean b = employeeList.stream()
.allMatch(e -> "info".equals(e.getStatus()));
System.out.println(b);
System.out.println("-------------------");
//anyMatch 检查是否匹配单个元素
boolean b1 = employeeList.stream()
.anyMatch(e -> "info".equals(e.getStatus()));
System.out.println(b1);
System.out.println("-------------------");
//noneMatch 检查没有匹配到元素
boolean b2 = employeeList.stream()
.noneMatch(e -> "asdas".equals(e.getStatus()));
System.out.println(b2);
System.out.println("-------------------");
//返回第一个元素
Optional<Employee> first = employeeList.stream()
.findFirst();
System.out.println(first);
System.out.println("-------------------");
//返回当前流中的任意元素
Optional<Employee> any = employeeList.stream()
.sorted((x,y) -> Integer.compare(x.getAge(),y.getAge()))
.findAny();
System.out.println(any);
}
排序
/**
* 排序
*sorted() 按照自然顺序进行排序
* sorted(Comparator com ) 按照比较器的顺序进行排序
*/
@Test
public void test4(){
List<Integer> integers = Arrays.asList(1, 5, 8, 7, 1, 2);
integers.stream()
.sorted()
.forEach(System.out::println);
employeeList.stream()
.sorted((x,y) -> Integer.compare(x.getAge(),y.getAge()))
.forEach(System.out::println);
}
归约和收集
归约
/**
* 归约
* reduce(T t,BinaryOperator) 第一个值是起始值
* reduce(BinaryOperator)
*/
@Test
public void test5(){
//计算工资总和 map-reduce
Double reduce = employeeList.stream()
.map(Employee::getSalary)
.reduce(0.00, (x, y) -> x + y);
System.out.println(reduce);
System.out.println("-------------------");
Optional<Double> reduce1 = employeeList.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(reduce1);
}
收集
/**
* 收集
* collect() 参数中可以传Collectors
*/
@Test
public void test6(){
//将名称取出来再加入到一个集合中去
List<String> list = employeeList.stream()
.map(Employee::getName)
.collect(Collectors.toList());
System.out.println(list);
System.out.println("----------------------");
//找出年龄最大的元素
Optional<Employee> collect = employeeList.stream()
.collect(Collectors.maxBy((x, y) -> Integer.compare(x.getAge(), y.getAge())));
System.out.println(collect);
System.out.println("----------------------");
// summarizingDouble 找出集合中该字段的总条数、总和、最小值、最大值、平均值
DoubleSummaryStatistics collect1 = employeeList.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(collect1);
System.out.println(collect1.getMax());
System.out.println(collect1.getAverage());
System.out.println("----------------------");
//joining 将取出的元素用指定的符号进行分割 并设置前缀和后缀
String collect2 = employeeList.stream()
.map(Employee::getName)
.collect(Collectors.joining(",","==","zz"));
System.out.println(collect2);
}
Optional
从 Java 8 引入的一个很有趣的特性是 Optional 类。Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException) —— 每个 Java 程序员都非常了解的异常。
本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空。
Optional 是 Java 实现函数式编程的强劲一步,并且帮助在范式中实现。但是 Optional 的意义显然不止于此。
参考文档https://www.cnblogs.com/zhangboyu/p/7580262.html
public static void main(String[] args) {
String name = "a";
//明确对象不为 null 的时候使用 of() of对象为null时会NullPointerException
Optional<String> opt = Optional.of(name);
//System.out.println(opt.get());
//如果对象即可能是 null 也可能是非 null,你就应该使用 ofNullable() 方法
Optional<String> opt2 = Optional.ofNullable(name);
//从 Optional 实例中取回实际值对象的方法之一是使用 get() 方法
//System.out.println(opt2.get());
//这个方法会在值为 null 的时候抛出异常。要避免异常,你可以选择首先验证是否有值
//验证是否有值 isPresent() ifPresent(Consumer<T>)
opt2.isPresent();
opt2.ifPresent(e -> System.out.println("a".equals(name)));
//Optional 类提供了 API 用以返回对象值,或者在对象为空的时候返回默认值。
// orElse 和 orElseGet 区别
//判断条件有值时
/**
* orElse
* new VO--
* orElseGet
* orElse执行了orElse里面的为空时的条件
* orElseGet只执行了不为空的条件
*/
HomeVo homeVo = new HomeVo();
homeVo.setHome_id(1);
homeVo.setChinese_name("1号");
System.out.println("orElse");
Optional.ofNullable(homeVo).orElse(SkcssApplicationTests.createVo());
System.out.println("orElseGet");
Optional.ofNullable(homeVo).orElseGet(() -> SkcssApplicationTests.createVo());
/**
*
* Java 9 增强
* Java 9 为 Optional 类添加了三个方法:or()、ifPresentOrElse() 和 stream()。
* or<Supplier<Optional>> homeVo对象为空时才会执行
* ifPresentOrElse(Consumer<T>,Runnable<T>) homeVo不为空执行Consumer,否则执行Runnable
* ifPresentOrElse() 方法需要两个参数:一个 Consumer 和一个 Runnable。如果对象包含值,会执行 Consumer 的动作,否则运行 Runnable。
*/
Optional.ofNullable(homeVo).or(() -> Optional.of(new HomeVo())).get();
Optional.ofNullable(homeVo).ifPresentOrElse(e -> new HomeVo(),() -> System.out.println("runnable"));
}
public static HomeVo createVo(){
System.out.println("new VO--");
return new HomeVo();
}