Java Lambda与Stream
羡羡ˇ 人气:0Lambda
Lambda 表达式是一个匿名函数,我们可以把 lambda 表达式理解为一段可以传递的代码(将代码段像数据一样传递)。使用它可以写出更简洁, 更灵活的代码。作为一种更紧凑的代码风格,使 java 语言的表达式能力得到的提升。
我们可以知道, Lambda表达式是为简化语法而存在的
ArrayList<String> list = new ArrayList<>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); list.sort(new Comparator<String>() { @Override public int compare(String o1, String o2) { return o2.compareTo(o1); } }); System.out.println(list);
这里有一个List集合 , 并添加了一些元素, 我们想对他进行排序, 并且按照降序的方式来排 , 在没接触Lambda表达式之前 ,我们是向上面那样去做的
上面这种方式是匿名内部类写法 , 调用sort()方法时, 要求传入一个比较器, Comparator是一个接口, 接口可以new吗? 肯定是不能的 , 所以这里是有一个隐藏的类去实现了Comparator接口, 并且重写了它里面的compare()方法 , 来制定我们的比较规则, 这个隐藏的类没有类名, 就是我们这里所说的匿名内部类 , 但方法也是不能作为参数去传递的, 所以我们new了这个匿名内部类的对象 , 包裹了实现后的方法
但是现在我们嫌这个写法太啰嗦了 ,我们使用Lambda来看看
// Lambda表达式 list.sort((o1,o2) -> {return o2.compareTo(o1);});
这就和上面的匿名内部类写法是一样的
Lambda表达式的结构 :
左侧:lambda 表达式的参数列表
右侧:lambda 表达式中需要执行的功能,即 lambda 体
(arg1, arg2...) -> { body }
(type1 arg1, type2 arg2...) -> { body }
常见例子
无参数,无返回值,lambda 体中只有一行代码时,{}可以忽略 () -> System.out.println("Hello World");
无参数,有返回值 () -> { return 3.1415 };
有参数,无返回值 (String s) -> { System.out.println(s); }
有一个参数,无返回值 s -> { System.out.println(s); }
有多个参数,有返回值 (int a, int b) -> { return a + b; }
有多个参数,表达式参数类型可以不写,jvm 可以根据上下文进行类型推断 (a, b) -> { return a - b; }
功能接口
功能接口上面一般会有这样一个注解标签@FunctionalInterface , 它表示此接口只有一个抽象方法, 当你注释的接口违反了 Functional Interface 的契约时,它可以用于编译器级错误
例如 : 我们刚使用的comparator接口就有这样的注解
Stream流
允许你以声明式的方式处理数据集合,可以把 它看作是遍历数据集的高级迭代器。此外与 stream 与 lambada 表达示结合后 编码效率与大大提高,并且可读性更强。
流更偏向于数据处理和计算,比如 filter、map、find、sort 等。简单来说,我们通过一个集合的 stream 方法获取一个流,然后对流进行一 系列流操作,最后再构建成我们需要的数据集合。
我们常常将Stream流与Lambda表达式结合来编码 , 那么如何来使用呢 ?
这里分为 3 步 :
1. 获得流
2. 中间操作
3. 终端操作
中间操作(往往对数据进行筛选)
- filter:过滤流中的某些元素,
- sorted(): 自然排序,流中元素需实现 Comparable 接口
- distinct: 去除重复元素
- limit(n): 获取 n 个元素
- skip(n): 跳过 n 元素,配合 limit(n)可实现分页
- map(): 将其映射成一个新的元素
终端操作(往往对结果集进行处理)
- forEach: 遍历流中的元素
- toArray:将流中的元素倒入一个数组
- Min:返回流中元素最小值 Max:返回流中元素最大值
- count:返回流中元素的总个数
- Reduce:所有元素求和
- anyMatch:接收一个 Predicate 函数,只要流中有一个元素满足条件则返回 true,否则返回
- falseallMatch:接收一个 Predicate 函数,当流中每个元素都符合条件时才返回 true,否则返回 false
- findFirst:返回流中第一个元素
- collect:将流中的元素倒入一个集合,Collection 或 Map
Integer[] arr = new Integer[]{1,4,3,2,5,5}; Arrays.stream(arr) //拿到流 .filter((a) -> {return a>3;}) //中间操作,过滤 .forEach((a) -> { //终端操作,遍历 System.out.println(a); }); Integer[] arr = new Integer[]{1,4,3,2,5,5}; Object[] objects = Arrays.stream(arr) .sorted().distinct() //排序并去重 .toArray(); //转数组 System.out.println(Arrays.toString(objects)); Integer[] arr = new Integer[]{1,4,3,2,5,5}; Integer max = Arrays.stream(arr).distinct() .max(((o1, o2) -> { //去重返回最大值 return o1 - o2; })).get(); //拿到这个值 //此处max为终端操作,返回的已经不是流,而是一个OPtion的对象 //它里面有一个get()方法可以返回这个值 System.out.println(max); Integer[] arr = new Integer[]{1,4,3,2,5,5}; long count = Arrays.stream(arr).distinct() .count(); //返回总个数 System.out.println(count); Integer[] arr = new Integer[]{1,4,3,2,5,5}; Integer i = Arrays.stream(arr).distinct() .reduce((o1, o2) -> { //所有元素求和 return o1 + o2; }) .get(); System.out.println(i);
这里需要注意的是中间操作的map()方法和终端操作的collect()方法
设计一个Apple类
public class Apple { private Integer num; private String name; private String color; }
并给出 构造 , set 和 get 方法 ,此处由于篇幅 原因省略
List<Apple> list = new ArrayList<>(); list.add(new Apple(100,"苹果1","红色")); list.add(new Apple(105,"苹果5","红色")); list.add(new Apple(104,"苹果4","红色")); list.add(new Apple(103,"苹果3","红色")); list.add(new Apple(102,"苹果2","红色"));
往一个list添加5个元素
List<String> collect = list.stream() //将属性的一列通过get方法映射成流 .map(Apple::getName) //转为一个list集合 .collect(Collectors.toList()); System.out.println(collect); List<Apple> collect = list.stream().sorted(((o1, o2) -> { //通过num属性自定义排序 return o1.getNum() - o2.getNum(); })) //转为一个list集合 .collect(Collectors.toList()); System.out.println(collect); Map<Integer, String> map = list.stream().sorted(((o1, o2) -> { return o1.getNum() - o2.getNum(); })) //转map, 第一个参数为键,第二个参数为值 .collect(Collectors.toMap(Apple::getNum, Apple::getName)); System.out.println(map);
到此关于Lambda表达式与Stream流就介绍完了,感谢阅读
加载全部内容