JAVA8新特性之Lambda表达式和Stream API详解

Java8新特性

简介:

  • 速度更快
  • 代码更少(新的语法lambda表达式)
  • 强大的stream api
  • 最大化减少空指针异常 optional

1.Lamada表达式

1.1说明:

lambda是一个匿名函数,也可以理解为接口的实例,一段可以像数据一样传递的代码,使Java语言更灵活,更紧凑

1.2 语法:

使用了新的语法操作符 ‘->’ ,该操作符的左侧是lambda表达式的参数部分,右侧是lambda体

1.2.1 几种基本语法

 * 格式一:无参,无返回值
 *      () -> System.out.println("hello lambda");
 *
 * 格式二:一个参数,无返回值(如果只有一个参数,则小括号可以不写:x -> System.out.println(x);)
 *      (x) -> System.out.println(x);
 *
 * 格式三:两个或以上的参数,有返回值,具lambda体中有多行语句,则需要放在{}*          Comparator<Integer> comparator = (x,y) -> {
 *             System.out.println("格式三 hello");
 *             return x-y;
 *          };
 * 格式四:如果lambda体中只有一条语句,则return和大括号{}可以不写
 *      Comparator<Integer> comparator1 = (x,y) -> Integer.compare(x,y);
 *
 * 格式五:lambda表达式的参数类型可以省略不写,JVM编译器可以根据上下文判断参数类型;
     
 * lambda表达式需要函数式接口的支持
 *      函数式接口:只有一个抽象方法的接口,可以使用@FunctionalInterface来检查是否是函数式接口,有该注解					修饰的接口,只能有一个抽象方法
 *
public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("hello world");
            }
        };
        r.run();
        System.out.println("===========");
        Runnable r1 = () -> System.out.println("hello lambda");
        r1.run();
     
        System.out.println("格式二=====================");
        Consumer<String> con = (x) -> System.out.println(x);
        con.accept("hello 格式二");
     
        System.out.println("格式三=====================");
        Comparator<Integer> comparator = (x,y) -> {
            System.out.println("格式三 hello");
            return Integer.compare(x,y);
        };
     
        Comparator<Integer> comparator1 = (x,y) -> Integer.compare(x,y);
        System.out.println("func=====================");
        Integer num = operation(10, (x) -> x*x );
        System.out.println(num);


    }

2.函数式接口

2.1定义:

​ 只包含一个抽象方法的接口,是函数式接口,可以通过lambda表达式来创建该接口的对象,可以使用@FunctionalInterface注解来检查一个接口是否是函数式接口

2.2举例

//Collections.sort()通过这个方法,对emps进行排序,先按年龄排序,年龄相同按姓名比
public static void test(){
    Collections.sort(emps,(e1,e2) -> {
        if(e1.getAge() == e2.getAge()){
            return e1.getName().compareTo(e2.getName());
        } else {
            return Integer.compare(e1.getAge(),e2.getAge());
        }
    });
    for(Employee emp: emps){
        System.out.println(emp.toString());
    }
}

2.3 四大内置核心函数式接口

  • Consumer :消费性接口 void accept(T t) ;
  • Supplier :供给型接口 T get();
  • Function:函数型接口 R apply(T t) ;
  • Predicate :断言型接口 boolean test(T t);
public class TestLambda4 {

    public static void main(String[] args) {
        Comsume con = new Comsume();
        double money = 1000.0;
        con.test(money,(x)-> System.out.println("消费:"+x));

        Supply supply = new Supply();
        Integer num = 10;
        List<Integer> list = supply.getList(num, () -> (int) (Math.random() * 10));
        System.out.println(list.toString());

        Predict predict = new Predict();
        boolean test = predict.test(120, (x) -> 100 < x && x < 200);
        System.out.println(test);
    }
}
//消费型接口
class Comsume{
    public void test(double money, Consumer<Double> consumer){
        consumer.accept(money);
    }
}

//供给型接口
class Supply{
    //产生指定个数的整数,并放入到集合中
    public List<Integer> getList(Integer num, Supplier<Integer> supplier){
        List<Integer> list = new ArrayList<>();
        for (int i=0;i<num;i++){
            Integer integer = supplier.get();
            list.add(integer);
        }
        return list;
    }
}
//断言型接口
class Predict{
    //判断所给数据,是否在某个范围内
    public boolean test(Integer num, Predicate<Integer> predicate){
        return predicate.test(num);
    }
}

3.方法引用与构造器

  • 说明:若lambda体中内容有方法已经实现了,可以使用方法引用,可以理解为lambda的另一种表现形式

  • 注意:lambda体中调用方法的参数列表与返回值类型,要与函数式接口抽象方法的参数和返回值一致;

    ​ 若lambda体中,参数列表的第一个参数是实例方法的调用者,第二个参数是实例方法的参数时,可以使用 类名::实例方法名

  • 方法引用:使用操作符 “::” 将方法名和对象或类的名字分隔开来

    三种情况:

    • 对象 :: 实例方法
    • 类 :: 静态方法
    • 类 :: 实例方法
  • 构造器引用

    ​ 格式:ClassName::new

    ​ 注意:调用哪个构造器,取决于函数式接口的抽象方法的参数,根据参数列表取决于调用哪个构造方法;

class Test1{
    //对象 :: 实例方法
    public void test01(String str){
        //Consumer consumer = (x) -> System.out.println(x);
        Consumer<String> consumer1 = System.out::println;
        consumer1.accept(str);
    }
    //对象 :: 实例方法
    public Integer getAge(){
        Employee emp = new Employee();
        Supplier<Integer> supplier = emp::getAge;
        return supplier.get();
    }
    //类 :: 静态例方法
    public void test03(){
//        Comparator comparator = (x,y)-> Integer.compare(x,y);
        Comparator<Integer> comparator = Integer::compare;
        int compare = comparator.compare(10, 20);
        System.out.println(compare);

    }
    //类 :: 实例方法
    //若lambda体中,参数列表的第一个参数是实例方法的调用者,第二个参数是实例方法的参数时,可以使用  类名::实例方法名
    public void test04(){
        BiPredicate<String,String> bp = (x,y)->x.equals(y);
        BiPredicate<String,String> bp1 = String::equals;
    }
    //构造器引用
    public void test05(){
        Supplier<Employee> sp = ()-> new Employee();
        Supplier<Employee> sp1 = Employee::new;
        sp1.get();
    }
    public void test06(){
        Function<Integer,String[]> f = (x)->new String[x];
        Function<Integer,String[]> f1 = String[]::new;
        String[] apply = f1.apply(10);
        System.out.println(apply.length);
    }
}

4.Stream API

  • 说明:流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列,集合讲的是数据,流讲的是计算!

  • 注意:

    • Stream 不会存储元素
    • Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream
    • Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
  • Stream操作的三个步骤

    • 创建流:一个数据源(如:集合、数组),获取一个流

      /*创建流
      Java8 中的 Collection 接口被扩展,提供了两个获取流的方法:
      	default Stream stream() : 返回一个顺序流
      	default Stream parallelStream() : 返回一个并行流
      	
      Java8 中的 Arrays 的静态方法 stream() 可以获取数组流
      	static  Stream stream(T[] array): 返回一个流
      
      有值创建流:可以使用静态方法 Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数
      	public static Stream of(T... values) : 返回一个流
      	
      有函数创建无限流:可以使用静态方法 Stream.iterate()和Stream.generate(), 创建无限流
      	public static Stream iterate(final T seed, final 
      UnaryOperator f)
      	public static Stream generate(Supplier s)
      
      */
      public void test01(){
          //通过Collection系列集合提供的stream()或者parallelStream()来获取流
          List<String> list = new ArrayList<>();
          Stream<String> stream = list.stream();
      
          //通过Arrays中的静态方法stream()获取数组流
          String[] strs = new String[5];
          Stream<String> stream1 = Arrays.stream(strs);
      
          //通过Stream的静态方法of()获取
          Stream<String> aa = Stream.of("aa", "bb", "cc");
      
          //创建无线流
          //迭代
          Stream<Integer> iterate = Stream.iterate(0, (x) -> x + 2);
          iterate.limit(20).forEach(System.out::println);
          //生成
          Stream<Double> generate = Stream.generate(() -> Math.random());
          generate.forEach(System.out::println);
      }
      
    • 中间操作:一个中间操作链,对数据源的数据进行处理

      中间操作可以连接起来形成一个流水线,中间操作不会执行任何处理,在终止操作时,执行全部处理

      //中间操作
      /*
      筛选与切片
      filter -- 接收lambda,从流中排除某些元素
      limit -- 截断流,使其元素不超过给定的数量(如果过滤到)
      skip(n) -- 跳过元素,返回一个排除掉前n个元素的流,如果元素个数不足n个,则返回一个空流,与limit(n)			  对应
      distinct -- 筛选,通过流所生成元素的hashcode()和equals()去除重复元素
      
      映射:
      map :接收lambda,将元素转换成其他形式或提取信息,接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素,
      
      排序:
      sorted():自然排序
      sorted(Comparator com):订制排序
      
       */
      public void test02(){
          //中间操作可以连接起来形成一个流水线,中间操作不会执行任何处理,在终止操作时,执行全部处理
          Stream<Employee> stream = emps.stream().filter(employee -> {
              System.out.println("Stream 中间操作");
              return employee.getAge() > 22;
          });
          stream.forEach(System.out::println);
      }
      public void test03(){
          emps.stream()
                  .filter(employee -> {
                      System.out.println("短路");
                      return employee.getAge()>18;
                  })
                  .limit(2)
                  .forEach(System.out::println);
      }
      public void test04(){
          emps.stream()
                  .filter((e) -> e.getAge()>22)
                  .skip(2)
                  .forEach(System.out::println);
      }
      //map映射
      public void test05(){
          List<String> list = Arrays.asList("aaa","bbb","ccc","ddd");
          list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
          emps.stream().map(employee -> employee.getName()).forEach(System.out::println);
      }
      
      //排序
      public void test06(){
          List<String> list = Arrays.asList("eee","bbb","aaa","ccc","ddd");
          list.stream().sorted().forEach(System.out::println);
      
          emps.stream().sorted( (emp1,emp2)-> {
              if(emp1.getAge() == emp2.getAge()){
                  return emp1.getName().compareTo(emp2.getName());
              }
              return Integer.compare(emp1.getAge(),emp2.getAge());
          }).forEach(System.out::println);
      }
      
    • 终止操作:一个终止操作,执行中间操作链,并产生结果

      /*
       * 查找与匹配
       * allMatch:检查是否匹配所有元素
       * anyMatch:检查是否至少匹配一个元素
       * noneMatch:检查是否没有匹配所有元素
       * findFirst:返回第一个元素
       * findAny:返回任意元素
       * count:返回元素总个数
       * max:返回流中最大值
       * min:返回流中最小值
       *
       * 规约:
       * reduce(T identity, BinaryOprator) / reduce(BinaryOprator) :可以将流中的元素反复结合
       * 起来,得到一个值
       * map-reduce模式:map和reduce连用
       *
       * 收集:
       * collect(Collector c):将流转为其他形式,接收一个Collector接口的实现,用于给stream中的元素做汇总的方法,Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,
       
      
      
      */
      class Test2{
          List<Employee> emps = Arrays.asList(
                  new Employee(100,"张三",20,5000.00, Employee.State.BUSY),
                  new Employee(100,"李四",22,6000.00,Employee.State.FREE),
                  new Employee(100,"王五",20,7000.00,Employee.State.BUSY),
                  new Employee(100,"朱六",25,8000.00,Employee.State.VOCATION),
                  new Employee(100,"样七",26,9000.00,Employee.State.BUSY)
          );
      
          public void test(){
              //allMatch匹配所有元素
              boolean b = emps.stream().allMatch(e -> e.getState().equals(Employee.State.BUSY));
              System.out.println(b);
              //anyMatch是否至少匹配一个元素
              boolean b1 = emps.stream().anyMatch(e -> e.getState().equals(Employee.State.VOCATION));
              System.out.println(b1);
              //noneMatch:检查是否没有匹配所有元素
              boolean b2 = emps.stream().noneMatch(e -> e.getState().equals(Employee.State.VOCATION));
              System.out.println(b2);
              //findFirst:返回第一个元素
              Optional<Employee> first = emps.stream().sorted((e1, e2) -> -Double.compare(e1.getMoney(), e2.getMoney())).findFirst();
              System.out.println(first.get());
      
              Optional<Employee> first1 = emps.stream().sorted((e1, e2) -> -Double.compare(e1.getMoney(), e2.getMoney())).findAny();
              System.out.println(first1.get());
      
              //count:返回元素总个数
              long count = emps.stream().count();
              System.out.println(count);
              //max:返回流中最大值
              Optional<Employee> max = emps.stream().max((e1, e2) -> Double.compare(e1.getMoney(), e2.getMoney()));
              System.out.println(max.get());
              //max:返回流中最大值
              Optional<Double> min = emps.stream().map(e -> e.getMoney()).min(Double::compare);
              System.out.println(min.get());
          }
      
          public void test02(){
              //reduce(T identity, BinaryOprator) / reduce(BinaryOprator) :可以将流中的元素反复结合起来,得到一个值
              List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
              Integer sum = list.stream().reduce(0, (x, y) -> x + y);
              System.out.println(sum);
      
              //map-reduce模式:map和reduce连用,Google用其进行网络搜索而得名
              Optional<Double> reduce = emps.stream().map(e -> e.getMoney()).reduce((x, y) -> x + y);
              reduce = emps.stream().map(Employee::getMoney).reduce(Double::sum);
              System.out.println(reduce.get());
          }
          //收集
          public void test03(){
              //将员工的名字收集到list集合中,可以
              List<String> collect = emps.stream().map(e -> e.getName()).collect(Collectors.toList());
              collect.forEach(System.out::println);
      
              //总数
              Long sum = emps.stream().collect(Collectors.counting());
              System.out.println(sum);
      
              //平均值
              Double avg = emps.stream().collect(Collectors.averagingDouble(Employee::getMoney));
              System.out.println(avg);
      
              //工资总和
              Double sumS = emps.stream().collect(Collectors.summingDouble(Employee::getMoney));
              System.out.println(sumS);
              
              //最大值
              Optional<Employee> max = emps.stream().collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getMoney(), e2.getMoney())));
              System.out.println(max.get());
      
              //最小值
              Optional<Double> min = emps.stream().map(e -> e.getMoney()).collect(Collectors.minBy(Double::compare));
              System.out.println(min.get());
      
          }
          //分组
          public void test04(){
              Map<Employee.State, List<Employee>> collect = emps.stream().collect(Collectors.groupingBy(Employee::getState));
              System.out.println(collect);
          }
      }
      

    收集:

  • collect(Collector c):将流转为其他形式,接收一个Collector接口的实现,用于给stream中的元素做汇总的方法,Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,
方法 返回类型 作用 举例
toList List 把流中元素收集到List List emps= list.stream()
.collect(Collectors.toList());
toSet Set 把流中元素收集到Set List emps= list.stream()
.collect(Collectors.toSet());
toCollection Collection 把流中元素收集到创建的集合 Collectionemps=list.stream().
collect(Collectors.toCollection(ArrayList::new));
counting Long 计算流中元素的个数 long count = list.stream().collect(Collectors.counting());
summingInt Integer 对流中元素的整数属性求和 int total = list.stream().collect(Collectors.summingInt(Employee :: getAge));
averagingInt Double 计算流中元素Integer属性的平均值 Double avg = emps.stream().collect(Collectors.averagingDouble(Employee::getMoney));
joining String 连接流中的每个字符串 String str= list.stream().map(Employee::getName).collect(Collectors.joining());
maxBy,minBy Optional 选择最大最小值 Optional max = list.stream().collect(Collectors.maxBy(comparingDouble(Employee::getMoney)))

你可能感兴趣的:(JAVA8新特性之Lambda表达式和Stream API详解)