1.1、什么是Lambda表达式?
lambda表达式可以理解为一种匿名函数的代替,lambda允许将函数作为一个方法的参数(函数作为方法方式传递),将代码像数据一样传递,目的是简化代码的编写。
lambda表达式需要函数式接口的支持
所谓函数式接口,是指只有一个抽象方法
另外JDK8也提供了一个注解,帮助我们编程时检查语法是否符合
@FunctionalInterface
lambda表达式的基本语法:
函数式接口 变量名 = (参数1,参数2...)->{
//方法体
};
案例1:
public static void main(String[] args) {
//匿名函数
Runnable runnable1 = new Runnable() {
@Override
public void run() {
System.out.println("run...");
}
};
new Thread(runnable1).start();
//lambda表达式第二种写法
Runnable runnable2 = ()->{
System.out.println("aaa......");};
new Thread(runnable2).start();
//lambda表达式第三种写法
new Thread(()->{
System.out.println("bbb......");}).start();
//第四种写法,如果方法体里面只有一条语句的时候,可以省去大括号
new Thread(()-> System.out.println("ccc......")).start();
}
案例2:
public static void main(String[] args) {
//匿名函数
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length()-o2.length();
}
};
TreeSet<String> treeSet = new TreeSet<>(comparator);
//lambda表达式
Comparator<String> comparator1 = (o1,o2)->o1.length()-o2.length();
TreeSet<String> treeSet1 = new TreeSet<>(comparator1);
//lambda表达式
TreeSet<String> treeSet2 = new TreeSet<>((o1,o2)->o1.length()-o2.length());
}
Lambda引入了新的操作符:->(箭头操作符),->将表达式分成两部分
左侧:(参数1,参数2…)表示参数列表;
右侧:{}内部是方法体;
1、形参列表的数据类型自动推断;
2、如果形参列表为空,只需保留();
3、如果形参只有1个,()可以省略,只需要参数的名称即可;
4、如果执行语句只有1句,且无返回值,{}可以省略,若有返回值,则若想省去{},则必须同事省略return,且执行语句也保证只有1句;
5、lambda不会生成一个单独的内部类文件;
6、lambda表达式若访问了局部变量,则局部变量必须是final的,若是局部变量没有加final关键字,系统会自动添加,此后在修改该局部变量,会报错;
Stream是Java8中处理数组,集合的抽象概念,它可以指定你希望对集合进行操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。
一个Stream表面上与一个集合很类似,集合中保存的是数据,而流设置的是对数据的操作。
Steam的特点:
1、Stream 自己不会存储元素。
2、Stream 不会改变源对象,相反,它们会返回一个持有结果的新Stream。
3、Stream 操作是延迟执行的,这意味看它们等到需要结果的时候才执行。
Stream遵循“做什么,而不是怎么做”的原则。只需要描述要做什么,而不用考虑程序是怎么实现的。
List<String> list = new ArrayList<>();
list.add("a");
list.add("hello");
list.add("stream");
//传统写法
int count = 0;
for (String s : list) {
if (s.length()>3){
count++;
}
}
System.out.println(count);
//StreamAPI结合lambda表达式
//1、链式编程
//2、函数式接口
//3、lambda表达式
long count1 = list.stream().filter((s) -> s.length() > 3).count();
System.out.println(count1);
1、创建一个Stream (创建)
2、在一个或多个步骤中,将初始Stream转化到另一个Stream的中间操作。(中间操作)
3、使用一个终止操作来产生一个结果,该操作会强制它之前的延迟操作立即执行,在这之后,该Stream就不会再被使用了。(终止操作)
上面已经演示了集合创建Stream的方式
这里面在补充一个重数组的方式
int[] array = new int[]{
1,2,3};
IntStream arrayStream = Arrays.stream(array);
long count2 = arrayStream.filter(i -> i > 2).count();
System.out.println(count2);
实体类:
package com.com.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
private String name;
private int age;
private int salary;
}
public static void main(String[] args) {
List<Employee> list = new ArrayList<>();
list.add(new Employee("zhangsan",20,1000));
list.add(new Employee("lisi",30,2000));
list.add(new Employee("wangwu",40,3000));
list.add(new Employee("wangwu",40,3000));
System.out.println("$$$$$$$$$筛选$$$$$$$$$");
//筛选
Stream<Employee> employeeStream = list.stream().filter(e -> e.getAge() > 30);
employeeStream.forEach(e-> System.out.println(e.getName()));
System.out.println("$$$$$$$$$获取第一个$$$$$$$$$");
//获取第一个
Stream<Employee> limit = list.stream().limit(1);
limit.forEach(System.out::println);
System.out.println("$$$$$$$$$跳过一个$$$$$$$$$");
//跳过一个
Stream<Employee> skip = list.stream().skip(1);
skip.forEach(System.out::println);
System.out.println("$$$$$$$$$去重$$$$$$$$$");
//自动调用equals和hashcode
Stream<Employee> distinct = list.stream().distinct();
distinct.forEach(System.out::println);
}
//map一接收Lambda,
//将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
Stream<String> stringStream = list.stream().map(e -> e.getName());
stringStream.forEach(System.out::println);
//小写转换大写
List<String> strings = Arrays.asList("a", "b", "c");
Stream<String> stringStream1 = strings.stream().map(String::toUpperCase);
stringStream1.forEach(System.out::println);
System.out.println("$$$$$$$$$第一种升序排序$$$$$$$$$");
Stream<Integer> sorted = list.stream().map(Employee::getAge).sorted();
sorted.forEach(System.out::println);
System.out.println("$$$$$$$$$第二种升序排序$$$$$$$$$");
List<Employee> collect = list.stream().sorted(Comparator.comparing(Employee::getAge)).collect(Collectors.toList());
collect.forEach(System.out::println);
System.out.println("$$$$$$$$$第二种降序排序$$$$$$$$$");
List<Employee> collect1 = list.stream().sorted(Comparator.comparing(Employee::getAge).reversed()).collect(Collectors.toList());
collect1.forEach(System.out::println);
System.out.println("$$$$$$$$$定制排序$$$$$$$$$");
Stream<Employee> sorted1 = list.stream().sorted((o1, o2) -> {
if (o1.getAge() == o2.getAge()) {
return o1.getName().compareTo(o2.getName());
} else {
return o1.getAge() - o2.getAge();
}
});
sorted1.forEach(System.out::println);
forEach
allMatch #检查是否匹配所有元素
anyMatch #检查是否至少匹配一个元素
noneMatch #检查是否没有匹配的元素
findFirst #返回第一个值
findAny #返回任意一个值
count #返回流中元素的总个数
max #返回流中最大的值
min #返回流中最小的值
System.out.println("$$$$$$$$$查询匹配$$$$$$$$$");
//检查是否匹配所有元素
boolean b1 = list.stream().allMatch(e -> e.getAge() > 30);
System.out.println(b1);
//检查是否至少匹配一个元素
boolean b2 = list.stream().anyMatch(e -> e.getAge() > 30);
System.out.println(b2);
//检查是否没有匹配的元素
boolean b3 = list.stream().noneMatch(e -> e.getName().equals("666"));
System.out.println(b3);
//返回第一个值
Optional<Employee> first = list.stream().findFirst();
if (first.isPresent()) {
Employee employee = first.get();
System.out.println(employee);
} else {
System.out.println("no value?");
}
//返回任意一个值
Optional<Employee> any = list.stream().filter(e->e.getAge()>30).findAny();
if (any.isPresent()) {
Employee employee = any.get();
System.out.println(employee);
} else {
System.out.println("no value?");
}
//返回流中元素的总个数
long count = list.stream().filter(e->e.getAge()>30).count();
System.out.println(count);
//返回流中最大的值
Optional<Employee> max = list.stream().max((x, y) -> x.getAge() - y.getAge());
System.out.println(max.get());
//返回流中最小的值
Optional<Employee> min = list.stream().min((x, y) -> x.getAge() - y.getAge());
System.out.println(min.get());
Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。
串行:
public static void main(String[] args) {
//初始化数据
int max = 1000000;
List<String> arrayList = new ArrayList<>(max);
for (int i = 0; i < max; i++) {
UUID uuid = UUID.randomUUID();
arrayList.add(uuid.toString());
}
//串行计算 耗时:558
/*long start = System.currentTimeMillis();
long count = arrayList.stream().sorted().count();
System.out.println(count);
long end = System.currentTimeMillis();
long millis = end - start;
System.out.println(millis);*/
//并行计算 耗时:289
long start = System.currentTimeMillis();
long count = arrayList.parallelStream().sorted().count();
System.out.println(count);
long end = System.currentTimeMillis();
long millis = end - start;
System.out.println(millis);
}
在Java Stream中,我们通常需要处理后的Stream转换成集合类,这个时候就需要用到stream.collect方法。collect方法需要传入一个Collector类型,要实现Collector还是很麻烦的,需要实现好几个接口。
于是Java提供了更简单的Collectors工具类方便我们使用构建Collector。
注意:Collectors不能再main方法执行,因为main方法是静态有冲突,使用单元测试即可。
下面具体讲解Collectors用法。
List<String> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<Users> usersList1 = new ArrayList<>();
List<Users> usersList2 = new ArrayList<>();
@Before
public void load(){
//初始数据集合 一个是里面元素无重复的集合,一个是里面元素有重复的集合
list1 = Arrays.asList("jack", "bob", "alice", "mark");
list2 = Arrays.asList("jack", "jack", "alice", "mark");
//无重复
usersList1.add(new Users(1,"张三",12));
usersList1.add(new Users(2,"李四",30));
usersList1.add(new Users(3,"王五",20));
usersList1.add(new Users(4,"赵六",12));
//重复
usersList2.add(new Users(1,"张三",12));
usersList2.add(new Users(2,"李四",30));
usersList2.add(new Users(3,"王五",20));
usersList2.add(new Users(4,"赵六",12));
usersList2.add(new Users(4,"赵六",12));
}
实体:
package com.test.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Users {
private int id;
private String name;
private int age;
}
将Stream转换为list。这里转换的list是ArrayList,如果想要转换成特定的list,需要使用toCollection方法
//转换toList
@Test
public void toList(){
List<String> collect1 = list1.stream().collect(Collectors.toList());
collect1.forEach(System.out::println);
System.out.println("---------------------------");
List<Users> collect2 = usersList1.stream().collect(Collectors.toList());
collect2.forEach(System.out::println);
}
toSet将Strem转换成Set,这里转换的是HashSet。如果需要特别指定Set,那么需要使用toCollection()方法。
因为Set中是没有重复元素的,如果我们使用list2集合数据来转换的话,会发现最终结果中只有一个jack。
//转换toSet
@Test
public void toSet(){
Set<String> collect1 = list1.stream().collect(Collectors.toSet());
collect1.forEach(System.out::println);
System.out.println("---------------------------");
Set<String> collect2 = list2.stream().collect(Collectors.toSet());
collect2.forEach(System.out::println);
System.out.println("---------------------------");
Set<Users> collect3 = usersList1.stream().collect(Collectors.toSet());
collect3.forEach(System.out::println);
System.out.println("---------------------------");
Set<Users> collect4 = usersList2.stream().collect(Collectors.toSet());
collect4.forEach(System.out::println);
}
toMap接收两个参数,第一个参数是keyMapper,第二个参数是valueMapper
//转换toMap
@Test
public void toMap(){
//无重复
Map<String, String> collect1 = list1.stream().collect(Collectors.toMap(String::new, s -> s));
collect1.forEach((key,value)->{
System.out.println("key:" +key+" ---- value:"+value);
});
System.out.println("---------------------------");
//重复
//如果stream中有重复的值,则转换会报IllegalStateException异常
//在toMap中添加第三个参数mergeFunction,来解决冲突的问题
Map<String, String> collect2 = list2.stream().collect(Collectors.toMap(String::new, s -> s,(item,mergeItem)->item));
collect2.forEach((key,value)->{
System.out.println("key:" +key+" ---- value:"+value);
});
System.out.println("---------------------------");
Map<Integer, String> collect3 = usersList1.stream().collect(Collectors.toMap(Users::getId, Users::getName));
collect3.forEach((key,value)->{
System.out.println("key:" +key+" ---- value:"+value);
});
System.out.println("---------------------------");
Map<Integer, String> collect4 = usersList2.stream().collect(Collectors.toMap(Users::getId, Users::getName, (item,mergeItem)->item));
collect4.forEach((key,value)->{
System.out.println("key:" +key+" ---- value:"+value);
});
}
上面的toMap,toSet转换出来的都是特定的类型,如果我们需要自定义,则可以使用toCollection(),下面我们转换成了LinkedList
//转换toCollection
@Test
public void toCollection(){
LinkedList<String> collect1 = list1.stream().collect(Collectors.toCollection(LinkedList::new));
collect1.forEach(System.out::println);
System.out.println("---------------------------");
LinkedList<Users> collect2 = usersList1.stream().collect(Collectors.toCollection(LinkedList::new));
collect2.forEach(System.out::println);
}
collectingAndThen允许我们对生成的集合再做一次操作,相当对Stream转换后再次操作
//collectingAndThen允许我们对生成的集合再做一次操作
@Test
public void collectingAndThen(){
List<String> collect1 = list1.stream().collect(Collectors.collectingAndThen(Collectors.toList(), s -> {
return new ArrayList(s);
}));
collect1.forEach(System.out::println);
System.out.println("---------------------------");
ArrayList collect2 = usersList1.stream().collect(Collectors.collectingAndThen(Collectors.toList(), u -> {
//转换list后进行改变某个元素的属性值
u.get(0).setAge(20);
return new ArrayList(u);
}));
collect2.forEach(System.out::println);
}
joining用来连接stream中的元素
//joining连接结合元素
@Test
public void joining(){
//第一种连接方式
String collect1 = list1.stream().collect(Collectors.joining());
System.out.println("第一种连接方式:"+collect1);
//第二种连接方式,使用空格进行连接,充当分隔符操作
String collect2 = list1.stream().collect(Collectors.joining(" "));
System.out.println("第二种连接方式:"+collect2);
//第三种连接方式,追加前缀和后缀
String collect3 = list1.stream().collect(Collectors.joining(" ","[","]"));
System.out.println("第三种连接方式:"+collect3);
System.out.println("---------------------------");
String collect4 = usersList1.stream().map(Users::getName).collect(Collectors.joining());
System.out.println(collect4);
String collect5 = usersList1.stream().map(Users::getName).collect(Collectors.joining(","));
System.out.println(collect5);
String collect6 = usersList1.stream().map(Users::getName).collect(Collectors.joining(",","{","}"));
System.out.println(collect6);
}
counting主要用来统计stream中元素的个数
//统计stream中的元素的个数
@Test
public void counting(){
Long collect1 = list1.stream().collect(Collectors.counting());
System.out.println(collect1);
System.out.println("---------------------------");
Long collect2 = usersList1.stream().collect(Collectors.counting());
System.out.println(collect2);
}
summarizing/Double/Long/Int为stream中的元素生成了统计信息,返回的结果是一个统计类
//summarizingDouble/Long/Int为stream中的元素生成了统计信息,返回的结果是一个统计类
@Test
public void summarizing(){
//summarizingInt 统计
IntSummaryStatistics collect1 = list1.stream().collect(Collectors.summarizingInt(String::length));
System.out.println(collect1);
System.out.println("---------------------------");
//summarizingDouble 统计
DoubleSummaryStatistics collect2 = list1.stream().collect(Collectors.summarizingDouble(String::length));
System.out.println(collect2);
System.out.println("---------------------------");
//summarizingLong 统计
LongSummaryStatistics collect3 = list1.stream().collect(Collectors.summarizingLong(String::length));
System.out.println(collect3);
System.out.println("---------------------------");
DoubleSummaryStatistics collect4 = usersList1.stream().collect(Collectors.summarizingDouble(Users::getAge));
System.out.println(collect4);
System.out.println("---------------------------");
LongSummaryStatistics collect5 = usersList1.stream().collect(Collectors.summarizingLong(Users::getAge));
System.out.println(collect5);
System.out.println("---------------------------");
IntSummaryStatistics collect6 = usersList1.stream().collect(Collectors.summarizingInt(Users::getAge));
System.out.println(collect6);
}
averaging/Double/Long/Int对stream中的元素做平均
//averaging/Double/Long/Int对stream中的元素做平均操作
@Test
public void averaging(){
//averaging Double 平均
Double collect1 = list1.stream().collect(Collectors.averagingDouble(String::length));
System.out.println(collect1);
System.out.println("---------------------------");
//averaging Long 平均
Double collect2 = list1.stream().collect(Collectors.averagingLong(String::length));
System.out.println(collect2);
System.out.println("---------------------------");
//averaging Int 平均
Double collect3 = list1.stream().collect(Collectors.averagingInt(String::length));
System.out.println(collect3);
System.out.println("---------------------------");
Double collect4 = usersList1.stream().collect(Collectors.averagingDouble(Users::getAge));
System.out.println(collect4);
System.out.println("---------------------------");
Double collect5 = usersList1.stream().collect(Collectors.averagingLong(Users::getAge));
System.out.println(collect5);
System.out.println("---------------------------");
Double collect6 = usersList1.stream().collect(Collectors.averagingInt(Users::getAge));
System.out.println(collect6);
}
summing/Double/Long/Int对stream中的元素做sum操作
//summing/Double/Long/Int对stream中的元素做sum操作
@Test
public void summing(){
//summingDouble 求和
Double collect1 = list1.stream().collect(Collectors.summingDouble(String::length));
System.out.println(collect1);
System.out.println("---------------------------");
//summingLong 求和
Long collect2 = list1.stream().collect(Collectors.summingLong(String::length));
System.out.println(collect2);
System.out.println("---------------------------");
//summingInt 求和
Integer collect3 = list1.stream().collect(Collectors.summingInt(String::length));
System.out.println(collect3);
System.out.println("---------------------------");
Double collect4 = usersList1.stream().collect(Collectors.summingDouble(Users::getAge));
System.out.println(collect4);
Long collect5 = usersList1.stream().collect(Collectors.summingLong(Users::getAge));
System.out.println(collect5);
Integer collect6 = usersList1.stream().collect(Collectors.summingInt(Users::getAge));
System.out.println(collect6);
}
maxBy()/minBy()根据提供的Comparator,返回stream中的最大或者最小值
//maxBy()/minBy()根据提供的Comparator,返回stream中的最大或者最小值
@Test
public void max(){
//可以使用默认Comparator.naturalOrder()自然计算,根据字母的大小, 这块使用Comparator.comparing(String::length)值的长度
Optional<String> collect1 = list1.stream().collect(Collectors.maxBy(Comparator.comparing(String::length)));
System.out.println(collect1);
System.out.println("---------------------------");
//可以使用默认Comparator.naturalOrder()自然计算,根据字母的大小, 这块使用Comparator.comparing(String::length)值的长度
Optional<String> collect2 = list1.stream().collect(Collectors.minBy(Comparator.comparing(String::length)));
System.out.println(collect2);
System.out.println("---------------------------");
Optional<Users> collect3 = usersList1.stream().collect(Collectors.maxBy(Comparator.comparing(Users::getAge)));
System.out.println(collect3);
Optional<Users> collect4 = usersList1.stream().collect(Collectors.minBy(Comparator.comparing(Users::getAge)));
System.out.println(collect4);
}
groupingBy根据某些属性进行分组,并返回一个Map
//GroupingBy根据某些属性进行分组,并返回一个Map
@Test
public void groupingBy(){
Map<Integer, Set<String>> collect = list1.stream().collect(Collectors.groupingBy(String::length, Collectors.toSet()));
collect.forEach((key,value)->{
System.out.println("key:" +key+" ---- value:"+value);
});
System.out.println("---------------------------");
usersList1.stream().collect(Collectors.groupingBy(Users::getAge)).forEach((key,value)->{
System.out.println("key:" +key+" ---- value:"+value);
});
}
PartitioningBy是一个特别的groupingBy,PartitioningBy返回一个Map,这个Map是以boolean值为key,从而将stream分成两部分,一部分是匹配PartitioningBy条件的,一部分是不满足条件的,结果被分成了两部分
//PartitioningBy是一个特别的groupingBy,PartitioningBy返回一个Map,
//这个Map是以boolean值为key,从而将stream分成两部分,一部分是匹配PartitioningBy条件的,一部分是不满足条件的
//结果被分成了两部分
@Test
public void partitioningBy(){
Map<Boolean, List<String>> collect1 = list1.stream().collect(Collectors.partitioningBy(s -> s.length() > 3));
collect1.forEach((key,value)->{
System.out.println("key:" +key+" ---- value:"+value);
});
System.out.println("---------------------------");
Map<Boolean, List<Users>> collect2 = usersList1.stream().collect(Collectors.partitioningBy(u -> u.getAge() > 20));
collect2.forEach((key,value)->{
System.out.println("key:" +key+" ---- value:"+value);
});
}
//分组后获取最大值或最小值
@Test
public void groupingMaxOrMin(){
//分组后去最大值
Map<Integer, Optional<Users>> collect = usersList1.stream().collect(Collectors.groupingBy(Users::getAge, Collectors.maxBy(Comparator.comparing(Users::getId))));
//分组后去最小值
Map<Integer, Optional<Users>> collect1 = usersList1.stream().collect(Collectors.groupingBy(Users::getAge, Collectors.minBy(Comparator.comparing(Users::getId))));
//打印最大值
collect.forEach((key,value)->{
System.out.println("key:" +key+" ---- value:"+value);
});
System.out.println("-----------------------");
//打印最小值
collect1.forEach((key,value)->{
System.out.println("key:" +key+" ---- value:"+value);
});
}
//分组后重新组装新对象
@Test
public void mapping(){
Map<Integer, List<String>> collect = usersList1.stream().collect(Collectors.groupingBy(Users::getAge, Collectors.mapping(u -> {
return u.getName();
}, Collectors.toList())));
collect.forEach((key,value)->{
System.out.println("key:" +key+" ---- value:"+value);
});
}
//单字段进行排序
@Test
public void sort(){
System.out.println("$$$$$$$$$$$倒序$$$$$$$$$$");
usersList1.stream().sorted(Comparator.comparing(Users::getAge).reversed()).collect(Collectors.toList()).forEach(System.out::println);
System.out.println("$$$$$$$$$$$升序$$$$$$$$$$");
usersList1.stream().sorted(Comparator.comparing(Users::getAge)).collect(Collectors.toList()).forEach(System.out::println);
}
//多字段排序,注意:排序的字段不能为空
@Test
public void comparator(){
//手动控制排序,(复制业务的时候,可以采用该方法)
//1、年龄倒序 2、id升序
Comparator<Users> usersComparator = Comparator.comparing(Users::getAge, (o1, o2) -> {
//倒序
return o2.compareTo(o1);
}).thenComparing(Users::getId, (o1, o2) -> {
//升序
return o1.compareTo(o2);
});
List<Users> collect = usersList1.stream().sorted(usersComparator).collect(Collectors.toList());
collect.forEach(System.out::println);
System.out.println("#@@@@@@@@@@@@@@@@@@@@@@@@@");
//* 第二种排倒序方法
//* Comparator.reverseOrder 倒叙
//* Comparator.naturalOrder 升叙
//1、年龄 倒序,2、id 倒序
Comparator<Users> usersComparator1 = Comparator.comparing(Users::getAge, Comparator.reverseOrder()).thenComparing(Users::getId, Comparator.reverseOrder());
List<Users> collect1 = usersList1.stream().sorted(usersComparator1).collect(Collectors.toList());
collect1.forEach(System.out::println);
}