1.lambda表达式的使用
前提:必须是接口,且只有一个方法需要实现
- 格式:
- ->:lambda的操作符 或者是 箭头操作符
- ->左边: lambda的形参列表(其实就是接口中的抽象方法的形参列表)
- ->右边:lambda体 (其实就是重写抽象方法的方法体)
- 3.lambda表达式的使用:(分为六种情况)
- 4.lambda表达式式的本质:作为函数式接口的实例
- 5.如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口
- 6.验证当前接口是不是函数式接口,可以看接口上面有没有注解 @FunctionalInterface
*/
public class LambdaTest02 {
//1.没有参数和返回值
@Test
public void test01(){
Runnable r1 = ()->{
System.out.println("你好");
};
r1.run();
}
//2.有参数没有返回值
@Test
public void test02(){
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("你好,请加油");
Consumer<String> consumer2 = (String s) ->{
System.out.println(s);
};
consumer2.accept("你是最棒的");
}
//3.数据类型可以省略,可以通过编译器推断出来,也叫类型推断
@Test
public void test03(){
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("你好,请加油");
Consumer<String> consumer2 = ( s) ->{
System.out.println(s);
};
consumer2.accept("你是最棒的");
}
//4.当只有一个参数时,小括号也可以省略
@Test
public void test04(){
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("你好,请加油");
Consumer<String> consumer2 = s ->{
System.out.println(s);
};
consumer2.accept("你是最棒的");
}
//5.lambda需要两个或以上的参数,多条执行语句,并且可以有返回值
@Test
public void test05(){
Comparator c1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
System.out.println(c1.compare(12, 23));
Comparator<Integer> c2 = ( o1, o2) -> {
return Integer.compare(o1, o2);
};
System.out.println(c2.compare(23, 45));
}
//6.当lambda只有一条执行语句时,return和{}都可以省略
@Test
public void test06(){
Comparator c1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
System.out.println(c1.compare(12, 23));
Comparator<Integer> c2 = ( o1, o2) -> Integer.compare(o1, o2);
System.out.println(c2.compare(23, 45));
}
}
2.方法引用
- 方法引用的使用
- 1.使用场景:当前传递给lambda体的草根,已经有实现的方法了,可以使用方法引用
- 2.方法引用,本质上就是lambda表达式,而lambda表达式作为函数式接口的实例,所以方法引用,也
- 3.使用格式 : 类::方法名
- 4.具体分为如下三种情况
对象::非静态方法
类::静态方法
类::非静态方法 - 5.方法引用使用的要求,要求接口中的抽象方法的形参列表和返回值类型与方法引用的形参列表和返回值类型相同
public class MethodRefTest {
/**
* 对象::非静态方法
* void accept(T t)
* void println(T t)
*/
@Test
public void test(){
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("nihao");
//方法引用
PrintStream out = System.out;
Consumer<String> consumer1 = out::println;
consumer1.accept("hello");
}
//类::静态方法
// Comparator中的 int compare(T t1,T t2);
// integer 中的 int compareTo(T t1,T t2)
@Test
public void test2(){
Comparator<Integer> c1 = (o1, o2) -> Integer.compare(o1,o2);
System.out.println(c1.compare(12,23));
Comparator<Integer> c2 = Integer::compare;
System.out.println(c2.compare(320,112));
}
//类::非静态方法
// Comparator中的 int compare(T t1,T t2);
// integer 中的 int compareTo(T t1,T t2)
@Test
public void test3(){
Comparator<Integer> c1 = (o1, o2) -> Integer.compare(o1,o2);
System.out.println(c1.compare(12,23));
Comparator<Integer> c2 = Integer::compareTo;
System.out.println(c2.compare(320,112));
}
}
3.构造器使用
- 构造器使用:
和方法引用类似,函数式接口的抽象方法的形参列表和构
抽象方法的返回类型即为构造器所属的类的类型 - 数组引用:
可以把数组看成一个特殊的类,写法与构造器引用一致
public class ConstructorRefTest {
/**
* 构造器引用
* supplier中的 T get()
* Employee的空参构造器: Employee
*/
@Test
public void test(){
Supplier<Employee> supplier = new Supplier<Employee>() {
@Override
public Employee get() {
return new Employee();
}
};
//lambda表达式
Supplier<Employee> supplier1 = ()->new Employee();
//构造器引用
Supplier<Employee> supplier2 = Employee::new;
}
//function中的 apply(T t)
@Test
public void test2(){
Function<String,Employee> fun = id -> new Employee(id);
Function<String,Employee> fun1 = Employee::new;
}
//数组引用
//function中的 apply(T t)
@Test
public void test3(){
Function<Integer,String[]> fun =new Function<Integer, String[]>() {
@Override
public String[] apply(Integer integer) {
return new String[integer];
}
};
Function<Integer,String[]> fun1 = integer -> new String[integer];
Function<Integer,String[]> fun2 = String[]::new;
}
}
4 .Stream到底是什么
Stream是数据渠道,用于操作数据源(集合,数组等)所生成的元素序列,“集合讲的是数据,Stream讲的是计算”
注意:
- Stream自己不会存储元素
- Stream不会改变源对象,相反,他们会返回一个持有结果的新stream
- Stream操作是延迟执行的,这意味着他们会等到需要结果的时候才执行
5.Stream的概念
Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找,过滤,和映射数据等操作,使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询,也可以使用Stream API来并行执行操作,简言之,stream API 提供了一种高效且易于使用的处理数据的方式
6.Stream的操作三个步骤
- 创建Stream
一个数据源(如:集合,数组),获取一个流
- 中间操作
一个中间操作链,对数据源的数据进行处理
- 终止操作(终端操作)
一旦执行终止操作,就会执行中间操作链,并产生结果,之后,不会在被使用
7.stream流创建的方式
- 1.Stream关注的是对数据的运算,与cpu打交代,集合关注的是数据的存储,与内存打交道
Stream自己不会存储元素
Stream不会改变源对象,相反,它们会返回一个持有结构的新stream
Stream操作是延时执行的,这意味这它们会等到需要结构的时候才执行 - 3.Stream执行流程
Stream的实例化
一系列的中间操作(过滤,映射,…)
终止操作 - 4.说明
一个中间操作链,对数据源的数据进行出来
一旦执行终止操作,就执行中间操作链,并产生结构,之后,不会在被使用
public class StreamApiTest {
//创建Stream方式一:通过集合
@Test
public void test1(){
List<Employee> employeeList = EmploymentData.getEmployment();
//返回一个顺序流:default Stream<E> stream() {
Stream<Employee> stream = employeeList.stream();
//返回一个并行流:default Stream<E> parallelStream()
Stream<Employee> parallelStream = employeeList.parallelStream();
}
//方式二:通过数组
@Test
public void test02(){
int[] arr = new int[]{1,2,3,4};
//过Array类的static IntStream stream(int[] array) 返回一个流
IntStream stream = Arrays.stream(arr);
}
//方式三:通过stream的of()
@Test
public void test03(){
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
}
//方式四:创建无限流
@Test
public void test04(){
//迭代
//public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
//遍历前10个偶数
Stream.iterate(0,t->t+2).limit(10).forEach(System.out::println);
//生成
//public static<T> Stream<T> generate(Supplier<T> s)
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
}
8.Stream流的中间操作
- 多个中间操作可以连接起来形成一个流水线,触发流水线上触发终止操作,否则中间
操作不会执行任何的处理,而在终止操作时一次性会全部处理,称为"惰性求职"
- 筛选与切片
filter(Predicate p) 接收lambda,从流中排除某些元素
distinct() 筛选,通过流生成元素的hashcode()和equals()去除重复元素
limit(long maxSize) 截断流,是元素不超过给定数量
skip(long n) 跳过元素,返回一个扔掉前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补
@Test
public void test(){
List<Employee> employeeList = EmploymentData.getEmployment();
Stream<Employee> stream = employeeList.stream();
//filter(Predicate p) 接收lambda,从流中排除某些元素
//从员工表中获取名字为java的员工信息
stream.filter(e -> e.getName().equals("java")).forEach(System.out::println);
System.out.println();
//limit(long maxSize) 截断流,是元素不超过给定数量
//从员工中获取前两条数据
employeeList.stream().limit(2).forEach(System.out::println);
System.out.println();
//skip(long n) 跳过元素,返回一个扔掉前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补
//从员工中获取前两条以后的信息
employeeList.stream().skip(2).forEach(System.out::println);
}
- 映射
map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
mapToDouble(ToDoubleFunction mapper) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream
mapToInt(ToIntFunction mapper);接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream
mapToLong(ToLongFunction mapper) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream
flatMap(Function mapper) 接收一个函数作为参数,将流中每个值都换成另一个流,然后把所有流连接成另一个流
@Test
public void test2(){
//map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
List<String> strings = Arrays.asList("aa", "bb", "cc");
//把每一个小写转换成大写字母
strings.stream().map(s -> s.toUpperCase()).forEach(System.out::println);
System.out.println();
//取出所有长度大于2的信息
List<Employee> list = EmploymentData.getEmployment();
Stream<Employee> stream = list.stream();
Stream<String> stringStream = stream.map(Employee::getName);
stringStream.filter(s -> s.length()>2).forEach(System.out::println);
Stream<Stream<Character>> streamStream = strings.stream().map(StreamMiddle::formStringToSteam);
//原本写法
// streamStream.forEach(new Consumer<Stream<Character>>() {
// @Override
// public void accept(Stream<Character> characterStream) {
// characterStream.forEach(new Consumer<Character>() {
// @Override
// public void accept(Character character) {
// System.out.println(character);
// }
// });
// }
// });
streamStream.forEach(s->s.forEach(System.out::println));
System.out.println();
//flatMap(Function mapper) 接收一个函数作为参数,将流中每个值都换成另一个流,然后把所有流连接成另一个流
strings.stream().flatMap(StreamMiddle::formStringToSteam).forEach(System.out::println);
}
//将字符串中的多个构成集合,转化成stream流
public static Stream<Character> formStringToSteam(String str){
List<Character> list = new ArrayList<>();
for (char c : str.toCharArray()) {
list.add(c);
}
return list.stream();
}
3.排序
sorted() 产生一个新流,其中按自然顺序排序
sorted(Comparator com) 产生一个新流,其中按比较器顺序排序
@Test
public void test03(){
//sorted() 产生一个新流,其中按自然顺序排序
List<Integer> list = Arrays.asList(12, 24, 56, 21);
list.stream().sorted().forEach(System.out::println);
//sorted(Comparator com) 产生一个新流,其中按比较器顺序排序
List<Employee> employeeList = EmploymentData.getEmployment();
//降序排列
employeeList.stream().sorted((e1,e2) -> e2.getId().compareTo(e1.getId())).forEach(System.out::println);
}
9.Stream流的终止操作
- 终端操作会从流的流水线生成结果,其结果可以是任何不是流的值,例如:List,Integer,甚至是void
- 流进行了终止操作后,不能再次使用
- 匹配与查找
allMatch(Predicate predicate) 检测是否匹配所有元素
anyMatch(Predicate predicate) 检测是否匹配任一元素
noneMatch(Predicate predicate) 检测是否没有匹配元素
findFirst() 返回第一个元素
findAny() 返回当前流中的任意元素
count() 返回流中的元素个数
max(Comparator c)返回流中最大值
min(Comparator c)返回流中最小值
forEach(consumer c) 内部迭代
@Test
public void test01(){
List<Employee> list = EmploymentData.getEmployment();
//allMatch(Predicate predicate) 检测是否匹配所有元素
//是否所有员工名字长度都大于2
boolean allMatch = list.stream().allMatch(employee -> employee.getName().length() > 2);
System.out.println(allMatch);
//anyMatch(Predicate predicate) 检测是否匹配任一元素
//检测员工里面有没有java
boolean anyMatch = list.stream().anyMatch(employee -> employee.getName().equals("java"));
System.out.println(anyMatch);
//noneMatch(Predicate predicate) 检测是否没有匹配元素
//检测员工里面有没有 wzj
boolean noneMatch = list.stream().noneMatch(employee -> employee.getName().equals("wzj"));
System.out.println(noneMatch);
//findFirst() 返回第一个元素
Optional<Employee> first = list.stream().findFirst();
System.out.println(first);
//findAny() 返回当前流中的任意元素
Optional<Employee> any = list.stream().findAny();
System.out.println(any);
//count() 返回流中的元素个数
long count = list.stream().count();
System.out.println(count);
//max(Comparator c)返回流中最大值
Optional<Employee> max = list.stream().max((e1, e2) -> e1.getName().compareTo(e2.getName()));
System.out.println(max);
//min(Comparator c)返回流中最小值
Optional<Employee> min = list.stream().min((e1, e2) -> e1.getName().compareTo(e2.getName()));
System.out.println(min);
//forEach(consumer c) 内部迭代
list.stream().forEach(System.out::println);
}
- 归约
T reduce(T identity, BinaryOperator accumulator) 可以将流中元素反复结合起来,得到一个值,返回T
T reduce(BinaryOperator accumulator) 可以将流中元素反复结合起来,得到一个值,返回optional
@Test
public void test02(){
// T reduce(T identity, BinaryOperator accumulator) 可以将流中元素反复结合起来,得到一个值,返回T
//计算1-10自然数的和
List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Integer reduce = asList.stream().reduce(0, new BinaryOperator<Integer>() {
// @Override
// public Integer apply(Integer integer, Integer integer2) {
// return integer + integer2;
// }
// });
Integer reduce = asList.stream().reduce(0, (i1, i2) -> i1 + i2);
System.out.println(reduce);
//T reduce(BinaryOperator accumulator) 可以将流中元素反复结合起来,得到一个值,返回optional<T>
//计算所有员工姓名的总长度
List<Employee> list = EmploymentData.getEmployment();
Stream<Integer> stream = list.stream().map(employee -> employee.getName().length());
//方法引用,类::静态方法
Optional<Integer> reduce1 = stream.reduce(Integer::sum);
System.out.println(reduce1);
}
- 收集
collect(Collector c) 将流转换为其他形式,接收一个Collector接口的方法,用给Stream中元素做汇总实现的方法
@Test
public void test03(){
//collect(Collector c) 将流转换为其他形式,接收一个Collector接口的方法,用给Stream中元素做汇总实现的方法
//查找名字长度大于2,并且返回list集合,set集合
List<Employee> list = EmploymentData.getEmployment();
//返回list
List<Employee> employeeList = list.stream().filter(e -> e.getName().length() > 2).collect(Collectors.toList());
employeeList.forEach(System.out::println);
//返回set
Set<Employee> employeeSet = list.stream().filter(e -> e.getName().length() > 2).collect(Collectors.toSet());
employeeList.forEach(System.out::println);
}
- 需要用到的工具类
public class Employee {
private String id;
private String name;
public Employee() {
}
public Employee(String id) {
this.id = id;
}
public Employee(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Employee{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
public class EmploymentData {
public static List<Employee> getEmployment(){
List<Employee> list = new ArrayList<>();
list.add(new Employee("1001","java"));
list.add(new Employee("1002","python"));
list.add(new Employee("1003","C++"));
list.add(new Employee("1004","C"));
list.add(new Employee("1005","go"));
return list;
}
}