Java8:Lambda表达式与Stream流
1、Lambda表达式
1.1 概述
我理解的lambda表达式,即是一种对于匿名内部方法的简易表示方法。
2.2 具体表述
例如如下代码,若想使用Runnable接口下的run方法
原始方法:先通过创建一个新的类implements去Runnable接口,再用新类的对象调用run方法。
class A implements Runnable{
@Override
public void run() {
System.out.println("原始方法");
}
}
A a = new A();
a.run();
进阶:我们知道,可以用匿名内部类的方法,将这两个步骤合二为一,进行一定的简化
Runnable r1 = new Runnable(){
@Override
public void run() {
System.out.println("匿名内部类方法");
}
};
r1.run();
最终:但以上的代码过于复杂,使用Lambda表达式替代:
(1)无参情况
Runnable r2 = () -> System.out.println("test2 is running");
//函数式接口,要求接口中只有一个方法
“()”括号内,书写该方法的参数(此处为无参方法),表示输入。
“ -> ” 箭头,表示在这个重写的接口方法中,具体要做什么。
例如此处含义为:什么也不输入,输出"test2 is running"
(2)有参情况
例如Comparator接口中的compare方法,如果我们想比较o1、o2两个数字的大小,则可以将两个数字传入进去。匿名内部类的写法如下:
Comparator<Integer> com1 = new Comparator<>(){
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
System.out.println(com1.compare(12,21));
lambda表达式的等效替代:
//lambda:省去不需要的部分,理解的话,相当于传入(o1,o2),箭头就是 return
Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1,o2);
System.out.println(com2.compare(32,21));
例如,此处的含义为,Comparator接口的对象com2,其内部方法compare,输入o1、o2,其方法return出这两个数的比较结果,即,调用compare方法。
(3) 函数化编程
/**
* 加减乘除
*/
public class Java8Tester {
public static void main(String args[]){
Java8Tester tester = new Java8Tester();
// MathOperation mathOperation = new MathOperation() {
// @Override
// public int operation(int a, int b) {
// return a + b;
// }
// };
// 类型声明
MathOperation addition = (int a, int b) -> a + b;
// 不用类型声明
MathOperation subtraction = (a, b) -> a - b;
// 大括号中的返回语句
MathOperation multiplication = (int a, int b) -> { return a * b; };
// 没有大括号及返回语句
MathOperation division = (int a, int b) -> a / b;
System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
System.out.println("10 / 5 = " + tester.operate(10, 5, division));
// 不用括号
GreetingService greetService1 = message ->
System.out.println("Hello " + message);
// 用括号
GreetingService greetService2 = (message) ->
System.out.println("Hello " + message);
greetService1.sayMessage("Runoob");
greetService2.sayMessage("Google");
}
interface MathOperation {
int operation(int a, int b);
}
//对于operate方法,输入的MathOperation对象调用其重写的方法operation
//如果正常情况下,则需要分别新建4个不同的类,实现MathOperation接口的方法,再创建四个对象进行加减乘除。
//使用Labmda表达式就简单多了
private int operate(int a, int b, MathOperation mathOperation){
return mathOperation.operation(a, b);
}
}
2、Stream流
2.1 概念
Stream就是来操作容器(Collection)的,比如List,或者数组,等。其具有以下性质:
- 1.Stream,是对数据运算,与cpu工作。
- 2.Stream不会自己储存元素,不会改变源对象,操作有延迟。
- 3.流程: Stream实例化 ->中间操作->终止操作
- 注意:终止操作以后不能直接返回中间操作
- 过滤条件:截断与跳过,筛选去重,函数映射,排序
2.2 如何将容器、数组等,转化为Stream流
(1)对于数组
用Arrays.stream(数组对象) 、或者Stream.of(数组内元素)
方法1:
int arr[] = new int[]{1,2,3,4,5};
IntStream stream = Arrays.stream(arr);
方法2:
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6);
(2)对于容器
采用“对象.stream()”方法
List<Integer> list = Arrays.asList(11,333,5555,7,9,88,1000,442424);
list.stream().sorted().forEach(System.out::println);
2.3 过滤条件:Stream流的API
例子1:数组+对象
Employee name1 = new Employee("name1", 111);
Employee name2 = new Employee("name2", 222);
Employee name3 = new Employee("name3", 333);
Employee arr1[] = new Employee[]{name1,name2,name3};
Stream<Employee> stream1 = Arrays.stream(arr1);
(1)过滤流 filter
(输入一个对象,名字任意,这个对象就是stream流里的对象。 返回的就是需要筛选的条件)
stream1.filter(employee -> employee.getAge() > 300).forEach(System.out::println);
(2)截断流 limit(n)
使元素不超过给定量n
Arrays.stream(arr1).limit(2).forEach(System.out::println);
(3)跳过元素 skip(n)
返回了一个流,这个流扔掉了前n个元素。元素不足会返回空
Arrays.stream(arr1).skip(1).forEach(System.out::println);
(4)哈希筛选 distinct()
通过流的元素的 hasCode()和equals() 来去除 重复 元素
list.stream().distinct().forEach(System.out::println);
例子2:List
List<String> list = Arrays.asList("AA", "BB", "CC", "DD", "EE");
(5)⭐映射map()
传入的容器的每个对象(关键,每个),随便起个名 —> 要对他做的函数
比如,想对list进行全部元素的“小写化”
list.stream().map(str -> str.toLowerCase()).forEach(System.out::println);
注意:map内的匿名内部函数,其实都是有return返回值的。如果仅仅是进行类似Set方法这类方法,想进行赋值的话,要将实体类前加上:
@Accessors(chain = true) 注解//执行完set方法后会return对象
(6)映射flatmap()
与map相比,flatmap能够将数组内的数组自动拆分为单个元素
list.stream().flatMap(StreamApi_::fromStringToStream).forEach(System.out::println);
(7)排序sorted()
//普通排序
List<Integer> list = Arrays.asList(11,333,5555,7,9,88,1000,442424);
list.stream().sorted().forEach(System.out::println);
//定制排序(按照对象的age)
List<Employee> listemp = new ArrayList<>();
listemp.add(new Employee("name1", 111));
listemp.add(new Employee("name5", 555));
listemp.add(new Employee("name2", 222));
listemp.add(new Employee("name3", 333));
//凡是排序都用到compare与comparable,输入两个参数。记住,compare是集合类的方法
listemp.stream().sorted((e1,e2)-> Integer.compare(e1.getAge(),e2.getAge())).forEach(System.out::println);
2.4 终止Api:匹配与查找
(1)匹配:返回布尔
即,匹配成功or失败。
List<Employee> listemp = new ArrayList<>();
listemp.add(new Employee("name1", 111));
listemp.add(new Employee("bame5", 555));
listemp.add(new Employee("came2", 222));
listemp.add(new Employee("dame3", 333));
//1.allMatch,判断全部是否满足
boolean allMatch = listemp.stream().allMatch(employee -> employee.getAge() > 100);
System.out.println(allMatch);
//2.anyMatch,判断是否存在一个
boolean anyMatch = listemp.stream().anyMatch(employee -> employee.getAge() > 500);
System.out.println(anyMatch);
//3.noneMatch,检查是否“没有”匹配的元素(没有则返回true)
boolean noneMatch = listemp.stream().noneMatch(employee -> employee.getName().startsWith("e"));
System.out.println(noneMatch);
//还有findFirst,findAny,count(返回匹配条件下的数目),max,min(要搭配compare
(2)归约reduce
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
Integer sum = list.stream().reduce(0, Integer::sum);//三个参数,初始值,第一个和第二个输入。
(3)收集数据collect
当我们对 Stream 流中的数据操作完成之后,如果需要将流的结果进行保存,方便我们接下来对结果的继续操作,该怎么办呢?
Stream 流提供了一个 collect() 方法,可以收集流中的数据到【集合】或者【数组】中去。
/**
* 收集Stream流中的数据到集合中
* 备注:切记Stream流只能被消费一次,流就失效了
* 如下只是示例代码
*/
public class CollectDataToCollection{
public static void main(String[] args) {
//Stream 流
Stream<String> stream = Stream.of("aaa", "bbb", "ccc", "bbb");
//收集流中的数据到集合中
//1.收集流中的数据到 list
List<String> list = stream.collect(Collectors.toList());
System.out.println(list);
//2.收集流中的数据到 set
Set<String> collect = stream.collect(Collectors.toSet());
System.out.println(collect);
//3.收集流中的数据(ArrayList)(不收集到list,set等集合中,而是)收集到指定的集合中
ArrayList<String> arrayList = stream.collect(Collectors.toCollection(ArrayList::new));
System.out.println(arrayList);
//4.收集流中的数据到 HashSet
HashSet<String> hashSet = stream.collect(Collectors.toCollection(HashSet::new));
System.out.println(hashSet);
}
}