java 8新特性λ表达式

本文深入探讨Java8的两大核心特性:λ表达式和Stream API。λ表达式简化了代码,提高了灵活性,使Java更接近函数式编程。Stream API则通过流操作增强了集合处理,特别适合批量数据操作。文章还介绍了方法引用、构造器引用和数组引用,以及Stream API的创建、中间操作和终止操作,包括筛选、映射、排序、查找、统计、归约和收集等。
摘要由CSDN通过智能技术生成

java 8新特性λ表达式和Stream API

λ表达式是java 8新增的一个特性,其实他就是一种新的语法,用新的代码形式实现了传统方式也可以实现的功能,将编码的方式渐渐的向函数式编程的方向发展,其主要特点是代码简洁、灵活、提升了java的语言表达能力。而stream则是使用流的方式对集合的操作做了增强,它专注于对集合对象进行各种非常便利、高效的聚合操作,或者大批量数据操作 。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。

λ表达式语法

  • 基本语法
(params) -> expression
(params) -> statement
(params) -> { statements }

箭头操作符将lambda表达式拆分成两部分;
左侧:lambda表达式的参数列表
右侧:lambda表达式中所需要执行的功能,即lambda体

  • 语法格式
package com.ge.lambda;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;
/*
 * 一、Lambda 表达式的基础语法:Java8中引入了一个新的操作符 "->" 该操作符称为箭头操作符或 Lambda 操作符
 * 箭头操作符将 Lambda 表达式拆分成两部分:
 *     左侧:Lambda 表达式的参数列表
 *     右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体
 * 语法格式一:无参数,无返回值
 *      () -> System.out.println("Hello Lambda!");
 * 语法格式二:有一个参数,并且无返回值
 *      (x) -> System.out.println(x)
 * 语法格式三:若只有一个参数,小括号可以省略不写
 *      x -> System.out.println(x)
 * 语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
 *      Comparator<Integer> com = (x, y) -> {
 *          System.out.println("函数式接口");
 *          return Integer.compare(x, y);
 *      };
 *
 * 语法格式五:若 Lambda 体中只有一条语句,有返回值, return 和 大括号都可以省略不写
 *      Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
 *
 * 语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
 *      (Integer x, Integer y) -> Integer.compare(x, y);
 *
 *
 * 二、Lambda 表达式需要“函数式接口”的支持
 * 函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。 可以使用注解 @FunctionalInterface 修饰
 *           可以检查是否是函数式接口
 */
public class TestLambda2 {
    /**
     * 无参 无返回值
     */
    public void test1(){
        Runnable r = () -> System.out.println("lambda");
        r.run();
    }
    /**
     * 有一个参数,并且无返回值
     */
    public void test2(){
        Consumer<String> con = (x) -> System.out.println(x);
        con.accept("有一个参数,并且无返回值");
    }
    /**
     * 若只有一个参数,小括号可以省略不写
     */
    public void test3(){
        Consumer<String> con = x -> System.out.println(x);
        con.accept("若只有一个参数,小括号可以省略不写");
    }
    /**
     * 有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
     */
    public void test4(){
        Comparator<Integer> comparator = (x,y) -> {
            System.out.println("函数式接口");
            return Integer.compare(x,y);
        };
        System.out.println(comparator.compare(5,6));
    }
    /**
     * 若 Lambda 体中只有一条语句,有返回值, return 和 大括号都可以省略不写
     */
    public void test5(){
        Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
        System.out.println(comparator.compare(5,6));
    }
    /**
     * Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
     */
    public void test6(){
        Comparator<Integer> comparator = (Integer x,Integer y) -> Integer.compare(x,y);
        System.out.println(comparator.compare(5,6));
    }
}

方法引用、构造器引用和数组引用

  1. 方法引用:若lambda体中的功能,已经有方法提供了实现,可以使用方法引用(可以理解为lambda表达式的另一种表现形式)
  • 对象的引用::实例方法名
  • 类名::静态方法名
  • 类名::实例方法名
    注意:①方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致!
    ②若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName
  1. 构造器引用:构造器的参数列表,需要与函数式接口中参数列表保持一致
  • 类名::new
  1. 数组引用
  • 类型[]::new
/**
 * 对象的引用 :: 实例方法名
 */
@Test
public void test1(){
    //消费型
    Consumer<String> consumer = (x) -> System.out.println(x);
    Consumer<String> consumer1 = System.out::println;
    consumer.accept("consumer:以前的写法");
    consumer.accept("consumer1:现在的写法");
    //供给型
    Student student = new Student(1l,"小明","男",12,new BigDecimal(2000));
    Supplier<String> supplier = student::getName;
    System.out.println(supplier.get());
}
/**
 * 类名 :: 静态方法名
 */
public void test2(){
    //函数型接口
    Function<Integer,String> fun = Student::getStr;
    System.out.println(fun.apply(100));
}
/**
 * 类名 :: 实例方法名   把类名当一个参数来处理
 */
public void test3(){
    //断言型接口
    BiPredicate<String,String>  biPredicate = (x,y) -> x.equals(y);
    System.out.println(biPredicate.test("222","333"));

    BiPredicate<String,String> biPredicate1 = String::equals;
    System.out.println(biPredicate1.test("222","333"));

    Function<Student,String> fun = (e) -> e.toString();
    System.out.println(fun.apply(new Student(1l,"小明","男",12,new BigDecimal(2000))));

    Function<Student,String> fun1 = Student::toString;
    System.out.println(fun.apply(new Student(1l,"小明","男",12,new BigDecimal(2000))));
}
/**
 * 构造器引用
 */
public void test4(){
   Supplier<Student> supplier = () -> new Student(1l,"小明","男",12,new BigDecimal(2000));
   System.out.println(supplier.get().toString());

   Supplier<Student> studentSupplier = Student::new;
   System.out.println(studentSupplier.get().toString());
}
/**
 * 数组引用
 */
public void test5(){
   //函数型接口
    Function<Integer,String[]> function = (x) -> new String[x];
    System.out.println(function.apply(3).length);

    Function<Integer,String[]> function1 = String[]::new;
    System.out.println(function1.apply(3).length);
}

Stream API

Stream API提供串行和并行两种操作,其中并行操作能发挥多核处理器的优势,使用fork/join的方式进行并行操作以提高运行速度。stream流的操作分为三个步骤:创建流、中间操作和中指操作。

创建流

/**
* default Stream stream() : 返回串行流
* default Stream parallelStream() : 返回并行流
*/
public void creatStream(){
    //1.通过Collection系列集合提供的stream()或者parallelStream();
    List<String> list=new ArrayList<String>();
    Stream<String> stream1 = list.stream();
    //2.通过Arrays中的静态方法Stream()获取数组流
    Integer[] ints=new Integer[10];
    Stream<Integer> stream2 = Arrays.stream(ints);
    //3.通过Stream类中的静态方法of()
    Stream<String> stream3 = Stream.of("aa", "bb", "cc");
    Stream<Object> empty = Stream.empty();
    //4.创建无限流
    //迭代
    Stream<Integer> stream4 = Stream.iterate(0, x -> x + 2);
    //生成
    Stream<Double> stream5 = Stream.generate(() -> Math.random());
}

中间操作

  1. 筛选和切片
/**
 * 中间操作--筛选和切片
 */
public void middle_(){
    //filer:过滤  Stream<T> filter(Predicate<? super T> predicate);
    System.out.println("-------------------------------------------");
    Stream<Student> filer = students.stream().filter(s -> s.getScore() > 60);
    filer.forEach(System.out::println);
    //limit:截断
    System.out.println("-------------------------------------------");
    Stream<Student> limit = students.stream().limit(2);
    limit.forEach(System.out::println);
    //skip:跳过
    System.out.println("-------------------------------------------");
    Stream<Student> skip = students.stream().skip(2);
    skip.forEach(System.out::println);
    //distinct:去重,通过流所生成元素的hashCode()和equals()去除重复的元素(也就是说Student要重写hashCode()和equals())
    System.out.println("-------------------------------------------");
    Stream<Student> distinct = students.stream().distinct();
    distinct.forEach(System.out::println);
    //peek:查看Stream流水线中的数据流的值
    System.out.println("-------------------------------------------");
    Stream<Integer> peek = students.stream().map(o->o.getScore()).peek(o-> System.out.print("原分数:"+o)).map(o->o+20);
    peek.forEach(o-> System.out.println(",新分数:"+o));
}
  1. 映射
/**
 * 中间操作--映射
 */
public void middle_map(){
    //map:映射,参数为Function<? super T, ? extends R> mapper
    System.out.println("-------------------------------------------");
    Stream<String>  map= students.stream().map(Student::getName);
    map.forEach(System.out::println);
    //flatmap:映射,参数为Function<? super T, ? extends Stream<? extends R>> mapper,将Function方法返回的每个流中的每个元素放到流中
    //map与flatmap的区别像是list的add()与addAll(),当然也不完全类似
    System.out.println("-------------------------------------------");
    Stream<Character> flatMap = students.stream().flatMap(s -> toBeCharacter(s.getName()));
    flatMap.forEach(System.out::print);
    //进一步学习map和flatmap
    String[] arrayOfWords = {"Goodbye", "World"};
    Stream<String> words = Arrays.stream(arrayOfWords);
    //map(Arrays::stream)得到的是一个流的列表
    List<Stream<String>> map1 = words.map(word -> word.split(""))
            .map(Arrays::stream)
            .distinct()
            .collect(toList());
    System.out.println("---------------------------------------map1:"+map1.get(0).collect(toList())+","+map1.get(1).collect(toList()));
    //流只能消费一次,所以words已经被消费了,需要重复创建
    Stream<String> words1 = Arrays.stream(arrayOfWords);
    //各个数组并不是分别映射成一个流,而是映射成流的内容
    List<String> flatMap1 = words1.map(word -> word.split(""))
            .flatMap(Arrays::stream)
            .distinct()
            .collect(toList());
    System.out.println("---------------------------------------flatMap1:"+flatMap1);

}
public static Stream<Character> toBeCharacter(String str){
    List<Character> list=new ArrayList<>();
    for (Character c:str.toCharArray()){
        list.add(c);
    }
    return list.stream();
}
  1. 排序
   /**
    * 中间操作--排序
    */
   @Test
   public void middle_sort(){
       //sorted():排序,数组中的对象需要实现Comparable
       //sorted(Comparator<? super T> comparator):排序,通过Comparator定制排序
       Stream<Student> sorted = students.stream().sorted((x, y) -> Integer.compare(x.getAge(), y.getAge()));
       sorted.forEach(System.out ::println);
   }

终止操作

  1. 查找和匹配
/**
* 终止操作--查找与匹配
*/
public void end_match_find(){
   //allMatch:检查是否匹配所有元素
   boolean allMatch = students.stream().allMatch(s -> s.getStatus().equals(Student.Status.Busy));
   System.out.println("是否所有人都很忙:"+allMatch);
   //anyMatch:检查是否匹配一个元素
   boolean anyMatch = students.stream().anyMatch(s -> s.getStatus().equals(Student.Status.Busy));
   System.out.println("是否有人很忙:"+anyMatch);
   //noneMatch:检查是否没有匹配所有元素
   boolean noneMatch = students.stream().noneMatch(s -> s.getStatus().equals(Student.Status.Busy));
   System.out.println("是否所有人都很闲:"+noneMatch);
   //findFirst:返回第一个元素
   Optional<Student> first = students.stream().findFirst();
   System.out.println("第一个元素:"+first.get());
   //findAny:返回当前流中的任意元素
   Optional<Student> any = students.parallelStream().filter(s -> s.getStatus().equals(Student.Status.Busy)).findAny();
   System.out.println("任一个元素:"+any.get());
}
  1. 统计
/**
* 终止操作--统计
*/
public void end_Statistics(){
   //count:返回流中元素的总个数
   long count = students.stream().count();
   System.out.println("学生人数:"+count);
   //max:返回流中最大值
   Optional<Student> max = students.stream().max((x, y) -> Integer.compare(x.getScore(), y.getScore()));
   System.out.println("分数最高的学生:"+max.get());
   //min:返回流中最小值
   Optional<Integer> min = students.stream().map(Student::getScore).min(Integer::compare);
   System.out.println("最低分数"+min.get());
   //sum(),实际是没有这个方法的,因为无法对stream<T>中的T可能并不是数值,无法对它做控制,解决方式如下
   //引入数值流,注意mapToInt()返回的对象是IntStream,不是stream<T>
   IntStream intStream = students.stream().mapToInt(Student::getScore);
   System.out.println("总分数"+intStream.sum());
   //将IntStream转为stream<T>,使用boxed()方法
   // Stream<Integer> stream = intStream.boxed();
}
  1. 归约
/**
* 终止操作--归约
*/
public void end_reduce(){
   //reduce:归约,元素计算
   //第一种,有初始值:T reduce(T identity, BinaryOperator<T> accumulator);
   Integer reduce = students.stream().map(s -> s.getScore()).reduce(0, (x, y) -> x + y);
   System.out.println("分数总和:"+reduce);
   //第二种,无初始值:Optional<T> reduce(BinaryOperator<T> accumulator);可能为空,所以返回Optional
   Optional<Integer> reduce1 = students.stream().map(s -> s.getScore()).reduce((x, y) -> x + y);
   System.out.println("分数总和:"+reduce1.get());
   Stream<Integer> stream = Arrays.stream(new Integer[2]);
   //Optional<Integer> reduce2 = stream.reduce((x, y) -> x + y);
   //System.out.println("结果是否为空:"+reduce2.isPresent());
   //求最大值,最小值
   Optional<Integer> maxOptional = students.stream().map(s -> s.getScore()).reduce(Integer::max);
   System.out.println("最大值 :"+maxOptional.get());

}
  1. 收集
/**
* 终止操作--收集
*/
public void end_collect(){
   //collection:收集,给stream中的元素做汇总,参数Collector<? super T, A, R> collector
   System.out.println("----------------------------list------------------------------");
   List<String> list = students.stream().map(s -> s.getName()).collect(toList());
   list.forEach(System.out::println);
   System.out.println("-------------------------set---------------------------------");
   Set<String> set = students.stream().map(s -> s.getName()).collect(Collectors.toSet());
   set.forEach(System.out::println);
   System.out.println("------------------------hashSet----------------------------------");
   HashSet<String> hashSet = students.stream().map(s -> s.getName()).collect(Collectors.toCollection(HashSet::new));
   hashSet.forEach(System.out::println);
   System.out.println("------------------------map----------------------------------");
   Map<String, Student> map = students.stream().collect(Collectors.toMap(Student::getName, e -> e,(e1,e2)->e1));
   for(String s:map.keySet()){
       System.out.println(map.get(s));
   }

}
  1. groupingby
/**
* 终止操作--收集--groupingBy
*/
public void end_collectors_groupingBy(){
   //分组
   System.out.println("---------------------原始写法-------group by------------------------------");
   Map<Student.Status, List<Student>> group1=new HashMap<Student.Status, List<Student>>();
   for(Student s: students){
       Student.Status status = s.getStatus();
       List<Student> students = group1.get(status);
       if(students==null){
           students=new ArrayList<Student>();
           group1.put(s.getStatus(),students);
       }
       students.add(s);
   }
   for (Student.Status s:group1.keySet()){
       System.out.println(s+":"+group1.get(s));
   }
   System.out.println("------------------------java8----group by------------------------------");
   Map<Student.Status, List<Student>> group = students.stream().collect(Collectors.groupingBy(Student::getStatus));
   for (Student.Status s:group.keySet()){
       System.out.println(s+":"+group.get(s));
   }
   //groupingBy(f)是groupingBy(f,toList())的缩写
   Map<String, List<Student>> groupBy = students.stream().collect(Collectors.groupingBy(o -> {
       if (o.getScore() < 60) return "不及格";
       else if (o.getScore() < 80) return "良";
       else return "优秀";
   }));
   for (String s:groupBy.keySet()){
       System.out.println(s+":"+groupBy.get(s));
   }
   System.out.println("------------------------java8----多级分组group by------------------------------");
   Map<Student.Status, Map<String, List<Student>>> groupBys = students.stream().collect(Collectors.groupingBy(Student::getStatus, Collectors.groupingBy(o -> {
       if (o.getScore() < 60) return "不及格";
       else if (o.getScore() < 80) return "良";
       else return "优秀";
   })));
   for (Student.Status s:groupBys.keySet()){
       System.out.println(s+":"+groupBys.get(s));
   }
   //与 groupingBy 联合使用的其他收集器
   System.out.println("--------------collectingAndThen,求每个状态中分数最高的学生-----------------------------");
   Map<Student.Status, Student> studentMap = students.stream().collect(Collectors.groupingBy(Student::getStatus, Collectors.collectingAndThen(
           Collectors.maxBy(Comparator.comparing(Student::getScore)), Optional::get)));
   for (Student.Status s:studentMap.keySet()){
       System.out.println(s+":"+studentMap.get(s));
   }
   System.out.println("--------------averagingInt,求每个状态的平均分-----------------------------");
   Map<Student.Status, Double> statusDoubleMap = students.stream().collect(Collectors.groupingBy(Student::getStatus, Collectors.averagingInt(Student::getScore)));
   for (Student.Status s:statusDoubleMap.keySet()){
       System.out.println(s+":"+statusDoubleMap.get(s));
   }
   System.out.println("--------------averagingInt,求每个状态的学生集合-----------------------------");
   Map<Student.Status, Set<String>> statusSetMap = students.stream().collect(Collectors.groupingBy(Student::getStatus, Collectors.mapping(Student::getName, Collectors.toSet())));
   for (Student.Status s:statusSetMap.keySet()){
       System.out.println(s+":"+statusSetMap.get(s));
   }
}
  1. partitioningBy
/**
* 终止操作--分区--partitioningBy
*/
public void end_collectors_partitioningBy(){
   //参数是Predicate
   Map<Boolean, List<Student>> map = students.stream().collect(Collectors.partitioningBy(o -> o.getScore() > 90));
   System.out.println("成绩大于90分的学生:"+map.get(true));
   //简单的分区也可以用filter来实现,但分区可以实现多级分区
   Map<Boolean, Set<String>> map1 = students.stream().collect(Collectors.partitioningBy(o -> o.getScore() > 90, Collectors.mapping(Student::getName, Collectors.toSet())));
   System.out.println("成绩大于90分的学生:"+map1.get(true));

}
  1. 收集器–reducing: 汇总归约
/**
* 终止操作--收集器--reducing: 汇总归约
*/
public void end_collectors_reducing(){
   //个数,底层:reducing(0L, e -> 1L, Long::sum)
   Long count = students.stream().collect(Collectors.counting());
   System.out.println("一共有多少个分数:"+count);
   //最高分
   Optional<Student> maxScore = students.stream().collect(Collectors.maxBy(Comparator.comparing(Student::getScore)));
   System.out.println("最高分:"+maxScore);
   //平均值
   Double average = students.stream().collect(Collectors.averagingInt(s -> s.getScore()));
   System.out.println("平均分:"+average);
   //总和
   Integer sum = students.stream().collect(Collectors.summingInt(s -> s.getScore()));
   System.out.println("总分:"+sum);
   //统计信息
   IntSummaryStatistics statistics = students.stream().collect(Collectors.summarizingInt(Student::getScore));
   System.out.println("统计信息:"+statistics);
   //连接字符串
   String studentNames = students.stream().map(Student::getName).collect(Collectors.joining(","));
   System.out.println("学生:"+studentNames);
   //广义归约reducing
   Integer sumScore = students.stream().collect(Collectors.reducing(0, Student::getScore, Integer::sum));
   System.out.println("总分:"+sumScore);
   Optional<Integer> sumScore1 = students.stream().map(Student::getScore).collect(Collectors.reducing(Integer::sum));
   System.out.println("总分:"+sumScore1.get());

}

内置函数式接口

  • Consumer : 消费型接口
    方法: void accept(T t)
  • Supplier : 供给型接口
    方法: T get();
  • Function<T, R> : 函数型接口
    方法: R apply(T t);
  • Predicate : 断言型接口
    方法: boolean test(T t);
import org.junit.Test;

import javax.print.DocFlavor;
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;

/*
 * Java8 内置的四大核心函数式接口
 *
 * Consumer<T> : 消费型接口
 *      void accept(T t);
 *
 * Supplier<T> : 供给型接口
 *      T get();
 *
 * Function<T, R> : 函数型接口
 *      R apply(T t);
 *
 * Predicate<T> : 断言型接口
 *      boolean test(T t);
 *
 */
public class TestLambda3 {

    /**
     * Consumer<T>消费型接口
     */
    @Test
    public void test1(){
        Consumer<String> consumer = x -> System.out.println(x);
        consumer.accept("consumer消费型接口");
    }
    /**
     * Supplier<T>供给型接口
     */
    @Test
    public void test2(){
        Supplier<Integer> supplier= () -> (int)(Math.random()*100);
        System.out.println(supplier.get());
    }
    /**
     * Function(T,R)函数型接口
     */
    @Test
    public void test3(){
        String resultstr = strHander("jjfsdjsjdsjiojwijf",(x) -> x.substring(2,5));
        System.out.println(resultstr);
    }
    public String strHander(String str, Function<String,String> fun){
        return  fun.apply(str);
    }

    /**
     * 断言型接口
     */
    @Test
    public void test4(){
        List<String> list = Arrays.asList("aaa","bbb","cccc","dddd");
        List<String> returnlist = getList(list,(x) -> x.length() > 3);
        System.out.println(Arrays.toString(returnlist.toArray()));
    }
    public List getList(List<String> list, Predicate<String> predicate){
        ArrayList<String> returnlist = new ArrayList();
        for(String str:list){
            if(predicate.test(str)){
                returnlist.add(str);
            }
        }
        return returnlist;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值