Lambda、stream

 

Lambda 

1.Lambda表达式概念

Lambda表达式是一个匿名函数,可理解为是一段可以传递的代码(即将函数像数据一样传递)。

Lambda表达式需要函数式接口(即只有一个抽象方法的接口)的支持。

Lambda操作符:->,该箭头一样的操作符将Lambda表达式拆分成两侧,

                          其中左侧写Lambda表达式的参数列表(接口中抽象方法的参数);右侧写Lambda表达式所需执行的功能(抽象方法的实现),即Lambda体。

 

2.Lambda表达式的基本语法

语法:

(parameters) -> expression

(parameters) ->{ statements; }

 

3.基础写法

我们先看几个简单的Lambda表达式的例子:

// 1. 不需要参数,返回值为 5 

     () -> 5

// 2. 接收一个参数(数字类型),返回其2倍的值 

      x -> 2 * x

// 3. 接受2个参数(数字),并返回他们的差值 

      (x, y) ->x –y

// 4. 接收2个Integer型整数,返回他们的和 

      (Integer x, Integer y) ->x + y

// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void) 

        (String s) ->System.out.print(s)

 

通过上述几个简单例子我们总结一下Lambda表达式的基本写法:

1).左侧类型可以不写;

2).左侧只有一个参数时小括号也可省略;

3)右侧只有一条语句时,大括号和return都可省略;

4)右侧有多条语句,必须要有大括号。

 

4.Lambda表达式用在for循环中

String[] names={"Mike","Mary","Eric","Lucy","Rose"};

List<String> students=Arrays.asList(names);

// 以前的循环方式 

for (String student: students) { 

  System.out.print(student+ "; "); 

   

//方式一: 使用 lambda 表达式以及函数操作

students.forEach((student) -> System.out.print(student+ "; ")); 

    

//方式二:使用双冒号操作符(Lambda表达式方法引用的第一种语法格式,下面会讲  )

students.forEach(System.out::println);

 

5.Lambda表达式的方法引用(双冒号操作符)

Lambda体中的内容已有方法实现,此时可以使用方法引用,有三种语法格式:

1)对象::实例方法名

例:Consumer<String> con=(x)->System.out.println(x);可以写为:

Consumer<String> con=System.out::println;//System.out即PrintWriter对象

2)类::静态方法名

例:Comparator<Integer> com=(x,y)->Integer.compare(x,y);可以写为:

Comparator<Integer> com=Integer::compare;

3)类::实例方法名

例:BiPredicate<String,String> bp=(x,y)->x.equals(y);

BiPredicate<String,String> bp=String::equals;

注意:只有当Lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用第3)种语法格式类::实例方法名。如上述例子中第一个参数x是实例方法x.equals(y)的调用者,第二个参数y是方法的参数。

 

数据流Stream

1.流的获取

1)通过集合Collection获取

List<Integer> list = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5));

 

Stream<Integer> stream = list.stream();

2)通过数组获取

String[] array = {"are","you","ok"};

 

Stream<String> stream = Array.stream(array);

//对于基本类型数组的处理

int[] array = {1,2,3,4,5};

 

//此时Arrays.stream(array)获取的是一个IntStream对象

Stream<Integer> stream = Arrays.stream(array).boxed();    

3)通过值获取(此方式存在缺陷)

Stream<String> stream = Stream.of("are","you","ok");

 

2.筛选filter

filter函数接收一个Lambda表达式作为参数,该表达式返回boolean,在执行过程中,流将元素逐一输送给filter,并筛选出执行结果为true的元素;

//筛选出列表中的非空项

 

List<String> list = Arrays.asList("are","you","","ok");

 

List<String> filted = list.stream()

                    .filter(x-> !x.empty())

                    .collect(Collectors.toList());

 

3.去重、截取、跳过

去重distinct:

List<String> list = Arrays.asList("are","you","you","ok");

List<String> distincted = list.stream()

                        .distinct()

                        .collect(Collectors.toList());

截取流的前n个元素: .limit(3)

跳过流的前n个元素: .skip(2)

 

4.映射 map

对流中的每个元素执行一个函数,使得元素转换成另一种类型输出。流会将每一个元素输送给map函数,并执行map中的Lambda表达式,最后将执行结果存入一个新的流中。 

如:将 list 中每一个 Integer类型元素自增后转化为 String类型

List<Integer> list = Arrays.asList(1,2,3,4,5);

 

List<String> result = list.stream()

                    .map(x->String.valueOf(++x))

                    .collect(Collectors.toList());

 

5.合并多个流 flatMap

List<String> list1 = .....

List<String> list2 = ...

List<List<String>> list = Arrays.asList(list1,list2);

 

//将list中的list1,list2合并为一个List<String>

List<String> listsum = list.stream()

                          .flatMap(List::stream)

                          .collect(Collectors.toList());

 

 

以下一个实际的应用例子:列出 list 中各不相同的单词

List<String> list = new ArrayList<String>();

list.add("I am a boy");

list.add("I love the girl");

list.add("But the girl loves another girl");

 

list.stream().map(line->line.split(" "))    //将每一个项分词,并映射为数组

//将每一个分项数组组合并到主流中,形成一个包含所有分项数组的总数组流

            .flatMap(Arrays::stream)      

            .distinct();                   //去重

            .forEach(System.out::println);   //打印

 

6.匹配元素

1) 是否匹配任一元素:anyMatch

2) 是否匹配所有元素:allMatch

3) 是否未匹配所有元素:noneMatch

 

7.获取元素

1) 获取任一元素 :findAny

2) 获取第一个元素:findFirst

Optional 对象介绍

Optional是Java8新加入的一个容器,这个容器只存1个或0个元素,它用于防止出现NullpointException,它提供如下方法:

  • isPresent()  判断容器中是否有值。
  • ifPresent(Consume lambda)  容器若不为空则执行括号中的Lambda表达式。
  • T get()  获取容器中的元素,若容器为空则抛出NoSuchElement异常。
  • T orElse(T other)  获取容器中的元素,若容器为空则返回括号中的默认值。

 

8.遍历流 forEach

forEach方法遍历流中每个元素,参数为一个Lambda表达式,用于对每一个遍历的元素执行的操作;

//输出10个随机数

Random random = new Random();

random.ints().limit(10).forEach(System.out::println);

 

posted on 2018-11-02 16:13  harderyao  阅读(131)  评论(0编辑  收藏  举报

导航