
一、Lambda表达式:
- Lambda表达式的使用
- 1、举例:(o1 , o2) -> Integer.compare(o1, o2);
- 2、格式:
-> : lambda的操作符- 左边:lambda的形参列表(其实就是接口中的抽象方法的形参列表)
- 右边:lambda体:(其实就是重写的抽象方法的方法体)
- 3、Lambda表达式的使用:
- 左边:lambda形参列表的参数类型可以省略;如果参数列表只有一个参数,其一对小括号也可以省略。没有参数或者有多个参数时,不能省略小括号。
- 右边:lambda体:应该使用大括号包裹。如果lambda体只有一条执行语句,(可能是return语句) , 可以省略这一对大括号以及return关键字。
- 4、lambda表达式的本质: 作为函数式接口的一个实例。要求必须是函数式接口。
- 5.如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。我们可以在一个接口上使用@FunctionalInterface 注解,这样做可以检查他是否是一个函数式接口。
- 6.所有以前用匿名实现类表示的现在都可以用lambda表达式来写。
Lambda表达式的六种情况
public class LambdaTest1 {
// 语法一:无参无返回值的。
@Test
public void test1() throws Exception {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("我爱北京天安门");
}
};
r1.run();
Runnable r2 = () -> System.out.println("我爱北京故宫");
r2.run();
}
// 语法二:有一个参数 无返回值。
@Test
public void test2() throws Exception {
Consumer<String> con = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con.accept("213");
System.out.println("*********************");
Consumer<String> con1 = (String s) -> System.out.println(s);
con1.accept("213");
}
// 语法三:数据类型可以省略,因为可由编译器推断的出 , 称为类型推断。
@Test
public void test3() throws Exception {
Consumer<String> con1 = (s) -> System.out.println(s);
con1.accept("213");
}
@Test
public void test4() throws Exception {
// 类型推断
ArrayList<String> strings = new ArrayList<>();
int[] arr = new int[]{1, 2, 3};
int[] arr1 = {1, 2, 3};
}
// 语法四:Lambda若只需要一个参数时,参数的小括号可以省略。
@Test
public void test5() throws Exception {
Consumer<String> con1 = s -> System.out.println(s);
con1.accept("213");
}
// 语法五:Lambda 需要两个或以上的参数,多条执行语句, 并且可以有返回值。
@Test
public void test6() throws Exception {
Comparator<Integer> com1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
System.out.println("**************");
Comparator<Integer> com2 = (o1, o2) ->{
System.out.println(o1);
System.out.println(o2);
return Integer.compare(o1,o2);
};
}
// 语法格式六:当Lambda体只有一条语句时 , return 与 大括号若有,都可以省略。
@Test
public void test7() throws Exception {
Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1,o2);
}
}
函数式接口
如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。
Lambda表达式的本质,作为函数式接口的实例。
- 消费型:Consumer void accept(T t) : 对类型为T的对象应用操作,包含方法 accept(T t)。
- 供给型:Supplier T get() : 返回类型为T的对象。包含方法T get()
- 函数型:Function<T , R> R apply(T t) : 对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t)
- 断定型:Predicate boolean test(T t) : 确定类型为T的对象是否满足某约束,并返回boolean值。包含方法:boolean test(T t)
- BiFunction<T,U,R> 参数 T U。返回R。对类型T、U参数应用操作,返回R类型的结果。包含方法 R apply(T t , U u)
- UnaryOperator Function子接口。 参数 T , 返回 T。对类型为T的对象进行一元运算,并返回T类型的结果。包含方法为:T apply(T t)
- BinaryOperator (BiFunction子接口):参数 T , T 返回 T。对类型为T的对象进行二元运算。并返回T类型的结果。包含方法 T apply(T t1,T t2)
- BiConsumer<T , U> : 参数 T、U,返回void。对类型为 T、U参数应用操作。包含方法为 void accept(T t , U u);
- BiPredicate<T , U>:参数 T , U 返回 boolean。包含方法为 boolean test (T t , U u);
- ToIntFunction 、 ToLongFunction 、 ToDoubleFunction 参数 T , 返回 int 、 long 、 double。分别计算int long double值的函数。
- IntFunction 、 LongFunction 、 DoubleFunction 参数 int long double。返回 R 。
当需要对一个函数式接口实例化的时候,可以使用Lambda表达式。
方法引用
方法引用定义及使用:
- 1.使用情景:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用。
- 2.方法引用本质上就是Lambda表达式,而我们的Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例。
- 3.使用格式: 类(或者对象):: 方法名
- 4.具体分为如下三种情况。
- 对象::非静态方法。
- 类::静态方法。
- 类::非静态方法。
- 5.方法引用使用要求:
- 要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型要相同。针对情况1、和情况2。
- 当函数式接口方法的第一个参数是需要引用方法的调用者,并且第二个参数是需要引用方法的参数(或无参数时):ClassName::methodName
方法引用的三大例子
public class MethodRefTest {
// 情况一:对象 :: 实例方法。
// Consumer 中的 void accept(T t)
// PrintStream中的void println(T t)
@Test
public void test1() throws Exception {
Consumer<String> con1 = str -> System.out.println(str);
con1.accept("北京");
System.out.println("***************");
PrintStream printStream = System.out;
Consumer<String> con2 = printStream::println;
con1.accept("beijing");
}
// Supplier中的 T get()
// Employee 中的String getName()
@Test
public void test2() throws Exception {
Employee employee = new Employee(1001 , "Tom" , 23 , 5600);
Supplier<String> sup1 = () -> employee.getName();
System.out.println(sup1.get());
System.out.println("***************");
Supplier<String> sup2 = employee::getName;
System.out.println(sup2.get());
}
// 情况二:类 :: 静态方法
// Comparator 中的 int compare(T t1 , T t2)
// Integer 中的 int compare(T t1 , T t2)
@Test
public void test3() throws Exception {
Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2);
int compare = com1.compare(12, 32);
System.out.println(compare);
System.out.println("***************");
Comparator<Integer> com2 = Integer::compare;
int compare1 = com2.compare(23, 12);
System.out.println(compare1);
}
// Function 中的 R apply(T t)
// Math中的Long round(Double d)
@Test
public void test4() throws Exception {
Function<Double , Long> fun1 = d -> Math.round(d);
System.out.println(fun1.apply(12.3));
System.out.println("***********");
Function<Double , Long> fun2 = Math::round;
System.out.println(fun2.apply(12.5));
}
// 情况三:类::实例方法。
// Comparator中的int compare(T t1 , T t2)
// String 中的int t1.compareTo(t2)
@Test
public void test5() throws Exception {
Comparator<String> com1 = (s1 , s2) -> s1.compareTo(s2);
System.out.println(com1.compare("abc", "abd"));
System.out.println("***************");
Comparator<String> com2 = String::compareTo;
}
// BiPredicate中的boolean test(T t1 , T t2);
// String 中的 boolean t1.equals(t2);
@Test
public void test6() throws Exception {
BiPredicate<String , String> pre1 = (s1 , s2) -> s1.equals(s2);
System.out.println(pre1.test("1", "2"));
System.out.println("***************");
BiPredicate<String , String> pre2 = String::equals;
System.out.println(pre2.test("123", "123"));
}
// Function 中的 R apply(T t)
// Employee 中的getName()
@Test
public void test7() throws Exception {
Function<Employee , String> fun1 = e -> e.getName();
Employee employee = new Employee(1001, "Jerry", 23, 6000);
System.out.println(fun1.apply(employee));
System.out.println("***************");
Function<Employee , String> fun2 = Employee::getName;
System.out.println(fun2.apply(employee));
}
}
构造器引用和数组引用
构造器引用结构:类名::new
数组引用结构:数组类型[] :: new
例子:
public class ConstructorRefTest {
// 构造器引用
@Test
public void test1() throws Exception {
Supplier<Employee> sup1 = () -> new Employee();
Supplier<Employee> sup2 = Employee::new;
}
// Function中d的 R apply(T t)
@Test
public void test2() throws Exception {
Function<Integer,Employee> fun1 = id -> new Employee(id);
Function<Integer,Employee> fun2 = Employee::new;
}
// BiFunction中的 R apply(T t , U u)
@Test
public void test3() throws Exception {
BiFunction<Integer , String , Employee> bifun1 = (id , name) -> new Employee(id , name);
BiFunction<Integer , String , Employee> bifun2 = Employee::new;
}
// 数组引用。
// Function 中的 R apply(T t)
Function<Integer , String[]> fun1 = length -> new String[length];
Function<Integer , String[]> fun2 = String[]::new;
}
StreamApi
- Stream关注的sh是对数据的运算。与CPU打交道。
- 集合关注的是数据的存储,与内存打交道的。
-
- Stream自己不会存储元素
-
- Stream不会改变源对象。相反,他们会fa返回一个持有结果的新stream对象。
-
- Stream 操作是延迟执行的,这意味着他们会等到需要结果的时候才执行。
-
- Stream执行流程:
-
- Stream实例化
-
- Stream一系列中间操作。(过滤,映射等)
-
- Stream终止操作。
-
- 中间操作是一个操作链,对数据源的数据进行处理。
- 一旦执行终止操作,就执行中间链操作,并产生结果。之后,不会再被使用。
创建stream的四种方式
// 创建Stream方式一:通过集合。
@Test
public void test1() throws Exception {
// default Stream<E> stream() : 返回一个顺序流。
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
// default Stream<E> parallelStream() : 返回一个并行流。
Stream<Employee> parallelStream = employees.parallelStream();
}
// 创建方式二:通过数组。
@Test
public void test2() throws Exception {
// 调用Arrays类的静态方法 static <T> Stream<T> stream(T[] array) : 返回一个流。
int[] arr = new int[]{1 , 2, 3};
IntStream intStream = Arrays.stream(arr);
DoubleStream doubleStream = Arrays.stream(new double[]{1, 2, 3});
Stream<Employee> stream = Arrays.stream(new Employee[]{new Employee(1001,"TOM") , new Employee(1002 , "Jerry")});
}
// 创建Stream方式三:通过Stream的of()
@Test
public void test3() throws Exception {
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8);
}
// 创建无限流
@Test
public void test4() throws Exception {
// 迭代
// public static <T> Stream<T> iderate(final T seed , final UnaryOperator<T> f)
// 遍历前十个偶数
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);
}
streamApi的中间操作
1、筛选与切片
| 方法 | 作用 |
|---|---|
| filter(Predicate p) | 接收lambda表达式,从流中排除某些元素。 |
| distinct() | 筛选,通过流所生成的元素的hashCode()和equals()去除重复元素。 |
| limit(long maxSize) | 截断流,使其元素不超过给定数量。 |
| skip(long n) | 跳过元素,返回一个人掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n) 互补 |
2、映射
| 方法 | 作用 |
|---|---|
| map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射为一个新元素。 |
| mapToDouble(ToDoubleFunction f) | 接收一个函数,该函数应用到每个元素上,产生一个新的DoubleStream |
| mapToInt(IntFunction f) | 接收一个函数,该函数应用到每个元素上,产生一个新的IntStream |
| mapToLong(LongFunction f) | 接收一个函数,该函数应用到每个元素上,产生一个新的LongStream |
| flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另外一个流。然后把所有的流连成一个流。 |
3、排序
| 方法 | 作用 |
|---|---|
| sorted() | 产生一个新的流,其中按自然排序。 |
| sorted(Comparator c) | 产生一个新的流,其中按比较器排序 |
终止操作
1、匹配与查找
| 方法 | 作用 |
|---|---|
| allMatch(Predicate p) | 检查是否匹配所有元素。 |
| anyMatch(Predicate p) | 检查是否至少匹配一个元素。 |
| noneMatch(Predicate p) | 检查是否没有匹配所有元素。 |
| findFirst() | 返回第一个元素。 |
| findAny() | 返回当前流中的任意元素。 |
| count() | 返回流中元素总数。 |
| max(Comparator c) | 返回流中最大值。 |
| min(Comparator c) | 返回流中最小值。 |
| forEach(Consumer c) | 内部迭代。 |
2、规约
| 方法 | 作用 |
|---|---|
| reduce(T iden , BinaryOperator b) | 可以将流中的元素反复结合起来得到一个值。 |
| reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回Optional |
3、收集
| 方法 | 作用 |
|---|---|
| toList | 返回List 把流中元素收集到List。 |
| toSet | 返回Set 把流中元素收集到set。 |
| toCollection | 返回Collection 把流中元素收集到创建的集合 |
| counting | 返回 Long 计算流中元素个数。 |
| summingInt | 返回Integer 对流中元素的整数属性求和。 |
| averagingInt | 返回Double 计算流中元素Integer属性的平均值。 |
| summarizingInt | 返回IntSummaryStatistics 收集流中Integer属性的统计值。如平均值。 |
| joining | 返回String 连接流中每个字符串 |
| maxBy | 返回Optional 根据比较器选择最大值。 |
| minBy | 返回Optional 根据比较器选择最小值。 |
| reducing | 返回规约产生的类型 从一个作为累加器的初始值开始,利用BinaryOperator与六中元素逐个结合,从而规约成单个值。 |
| collectingAndThen | 返回转换函数返回的类型。包裹另一个接收器。对其结果转换函数。 |
| groupingBy | 返回Map<K , List> 根据某属性值对流分组。属性为K,结果为V |
| partitioningBy | 返回Map<Boolean , List> 根据true或false进行分区。 |
Optional解决空指针为生
package com.starcpdk.optionaltest2;
import org.junit.Test;
import java.util.Optional;
/**
* @Author 姚云峰
* @Email
* @Date 2022/11/8 11:15
* @Version 1.0
*/
public class OptionalTest {
@Test
public void test1() throws Exception {
Optional<Object> op1 = Optional.empty();
if (op1.isPresent()) { // Optional封装的数据是否包含数据。
System.out.println("数据为空");
}
System.out.println(op1.isPresent());
// 如果Optional封装的数据value 为空 , 则get方法报错。否则,value不为空时,返回value。
System.out.println(op1.get());
}
@Test
public void test2() throws Exception {
String str = "hello";
Optional<String> op1 = Optional.ofNullable(str);
System.out.println(op1.get());
// get方法通常与of()方法使用。用于获取内部封装的数据value。
}
@Test
public void test3() throws Exception {
String str = "北京";
str = null;
Optional<String> op1 = Optional.ofNullable(str);
String str1 = op1.orElse("shanghai");
System.out.println(str1);
}
}
package com.starcpdk.optionaltest;
import org.junit.Test;
import java.util.Optional;
/**
* @Author 姚云峰
* @Email
* @Date 2022/11/5 15:00
* @Version 1.0
*/
/**
* Optional类: 为了程序中避免出现空指针异常而创建的。
*
* 常用方法:
* ofNullable(T t)
* orElse(T t)
*/
public class OptionalTest {
@Test
public void test1() throws Exception {
/**
* Optional.of(T t) : 创建一个Optional实例,t必须非空。
* Optional.empty() : 创建一个空的Optional 实例
* Optional.ofNullable(T t) : t 可以为null。
*
*/
Girl girl = new Girl();
// of(T t) : 保证 t 是非空的。
Optional<Girl> optionalGirl = Optional.of(girl);
System.out.println(optionalGirl);
girl = null;
// Optional.ofNullable(T t) 中的 t 可以为空。
Optional<Girl> optionalGirl1 = Optional.ofNullable(girl);
System.out.println(optionalGirl1);
// orElse(T t1) : 如果当前的Optional内部封装的t是非空的。则返回 内部的t
// 如果内部的t是空的,则返回orElse方法中的参数 t1。
Girl girl1 = optionalGirl1.orElse(new Girl("赵丽颖"));
System.out.println(girl1);
}
public String getGirlName(Boy boy) {
return boy.getGirl().getName();
}
@Test
public void test2() throws Exception {
Boy boy = new Boy();
String girlName = getGirlName(boy);
System.out.println(girlName);
}
// 优化后的getGirlName
public String getGirlName1(Boy boy) {
if (boy != null) {
Girl girl = boy.getGirl();
if (girl != null) {
return girl.getName();
}
}
return null;
}
// 使用Optional类优化后的getGirlName
public String getGirlName2(Boy boy) {
Optional<Boy> boyOptional = Optional.ofNullable(boy);
// 此时的boy1一定非空。
Boy boy1 = boyOptional.orElse(new Boy(new Girl(" ")));
Girl girl = boy1.getGirl();
Optional<Girl> girlOptional = Optional.ofNullable(girl);
// 此时的girl1一定非空。
Girl girl1 = girlOptional.orElse(new Girl("古力娜扎"));
return girl1.getName();
}
@Test
public void test3() throws Exception {
Boy boy = null;
boy = new Boy();
boy = new Boy(new Girl("哈哈哈哈"));
String girlName = getGirlName2(boy);
System.out.println(girlName);
}
}
4517

被折叠的 条评论
为什么被折叠?



