Lambda表达式
Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以
传递的代码(将代码像数据一样进行传递)。
- Lambda的使用:
- 格式:
-
-> :lambda操作符 或 箭头操作符
-
->左边:lambda形参列表 (其实就是接口中的抽象方法的形参列表)
-
->右边:lambda体 (其实就是重写的抽象方法的方法体)
- Lambda表达式的使用:(分为6种情况介绍)
-
语法格式一:无参,无返回值
public void test1(){
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("我是Runnable");
}
};
r1.run();
System.out.println("*************");
Runnable r2 = () -> System.out.println("我是Lambada中的Runnable");
r2.run();
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("inside runnable using anonymous inner class");
}
}).start();
new Thread(() -> System.out.println("inside runnable using a lambda")).start();
Runnable r = () -> System.out.println("using a lambda as a variable");
new Thread(r).start();
}/
-
语法格式二:Lambda 需要一个参数,但是没有返回值,Consumer也是函数式接口中的一个
public void test2(){
Consumer<String> con = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con.accept("我的世界");
System.out.println("**********************");
Consumer<String> con1 = (String s) -> {
System.out.println(s);
};
con1.accept("我的世界从此很美");
}
-
语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
public void test3(){
Consumer<String> con1 = (String s) -> {
System.out.println(s);
};
con1.accept("我的世界从此很美");
System.out.println("****************");
Consumer<String> con2 = (s) -> {
System.out.println(s);
};
con2.accept("我的世界从此很美");
}
-
语法格式四:Lambda 若只需要一个参数时,参数的小括号可以省略
public void test4(){
Consumer<String> con1 = (s) -> {
System.out.println(s);
};
con1.accept("一个是听得人当真了,一个是说的人当真了");
System.out.println("*******************");
Consumer<String> con2 = s -> {
System.out.println(s);
};
con2.accept("一个是听得人当真了,一个是说的人当真了");
}
-
语法格式五:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
public void test5(){
Comparator<Integer> com1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
}
};
System.out.println(com1.compare(12,21));
System.out.println("*****************************");
Comparator<Integer> com2 = (o1,o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
System.out.println(com2.compare(12,6));
}
-
语法格式六:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略
public void test6(){
Comparator<Integer> com1 = (o1,o2) -> {
return o1.compareTo(o2);
};
System.out.println(com1.compare(12,6));
System.out.println("*****************************");
Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);
System.out.println(com2.compare(12,21));
}
总结:
->左边:lambda形参列表的参数类型可以省略(类型推断);如果lambda形参列表只有一个参数,其一对()也可以省略
->右边:lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return语句),省略这一对{}和return关键字
函数式接口
- Lambda表达式的本质:作为函数式接口的实例
- 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口。
- 所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。
-
Lambda 就是为函数式接口服务的
Java中内置4大函数接口
1.消费型接口
Consumer:消费型接口 单一抽象方法为:void accept(T t);
方法 | 描述 |
---|---|
void accept(T t) | 对给定的参数执行此操作 |
default Consumer andThen(Consumer<? super T> after) | 返回一个组合的 Consumer ,按顺序执行该操作,然后执行 after操作(用于函数复合) |
-
作用:消费某个对象**(传入一个泛型参数,不返回任何值)**
-
举例:forEach: Iterable接口的foeEach方法 需要传入Consumer,大部分集合类都实现了该接口,用于返回Iterator对象进行迭代。
java.util.function包还定义了其他三种Consumer的基本变体(用于处理基本数据类型),以及一种双参数形式,BiConsumer接口的accept方法传入两个泛型参数,这两个泛型参数应为不同的类型。
接口 | 单一抽象方法 |
---|---|
IntConsumer | void accept(int x) |
DoubleConsumer | void accept(double x) |
LongConsumer | void accept(long x) |
BiConsumer | void accept(T t,U u) |
@Test
public void test1(){
happy(1000,(x) -> System.out.println("需要消费" + x + "元!"));
}
//这个就是不用lambda表达式的写法
public void test1(){
happy(1000, new IntConsumer() {
@Override
public void accept(int x) {
System.out.println("需要消费" + x + "元!");
}
});
//首先我定义了一个happy方法,里面有2个参数,一个为int,一个为
//消费型接口(传入一个值无返回值)当我在test1调用的时候就相当于我传入了一个值为X,
//返回了一个输出语句,而根据我的happy方法可以得知我传入的值是我
//第一个参数money,所以这个输出就是 需要消费1000元!
public void happy(int money, IntConsumer con){
con.accept(money);
}
//方便理解我们把原始方法,就相当于我们创建了一个实例,只是用Lambda
//表达式的方式把他进行输出。
happy(1000, new IntConsumer() {
@Override
public void accept(int x) {
System.out.println("需要消费" + x + "元!");
}
});
2.供给型接口
Supplier:供给型接口 T get();
方法 | 描述 |
---|---|
T get() | 获得结果 |
- 作用:创建一个对象(工厂类)(不传入参数,返回一个值)
- 举例:Optional.orElseGet(Supplier<? extends T>):当this对象为null,就通过传入supplier创建一个T返回。(Optional类是一种容器对象,要么包装值,要么为空)
其他Supplier接口:(返回基本数据类型的数据)
接口 | 单一抽象方法 |
---|---|
IntSupplier | int getAsInt() |
DoubleSupplier | double getAsDouble(double x) |
LongSupplier | long getAsLong(long x) |
BooleanSupplier | boolean getAsBoolean(T t,U u) |
// 产生指定个数的整数,并放入集合中
@Test
public void test2(){
//就想到与我产生了一个随机数,然后一共10次,存入的就是我lambda表达式返回的值。然后相当于存入为list里面的值就是我产生的值,和上面的方法类似下同
List<Integer> numList = getNumList(10,() -> (int)(Math.random() * 100));
for (Integer num:numList){
System.out.println(num);
}
}
//首先我定义了一个getNumList一个方法,里面2个参数,一个是int,一个是supplier接口,创建一个List,把生成的num个元素存入一个list中。
//我传入值为空,返回一个值
public List<Integer> getNumList(int num, Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for(int i = 0;i<num;i++){
Integer n = sup.get();
list.add(n);
}
return list;
}
3.函数式接口
Function<T,R>:函数型接口 R apply(T t);
方法 | 描述 |
---|---|
default Function<T,V> andThen(Function<? super R,? extends V> after) | 返回一个组合函数,首先将该函数应用于其输入,然后将 after函数应用于结果(先执行当前对象的apply方法,再执行after对象的方法)。 |
R apply(T t) | 将此函数应用于给定的参数。 |
default Function<V,R> compose(Function<? super V,? extends T> before) | 返回一个组合函数,首先将 before函数应用于其输入,然后将此函数应用于结果(先执行before对象的apply,再执行当前对象的apply,将两个执行逻辑串起来)。 |
static Function<T,T> identity() | 返回一个总是返回其输入参数的函数。 |
- 作用:实现一个“一元函数”,即传入一个值经过函数的计算返回另一个值。(传入一个参数,返回一个值)
public String strHandler(String str, Function<String,String> fun){
return fun.apply(str);
}
@Test
public void test3(){
String newStr = strHandler("\t\t\t dfns;f ",(x) -> x.trim());
System.out.println(newStr);
}
其他Function接口(BiFunction接口定义了两个泛型输入类型和一个泛型输出类型)
接口 | 单一抽象方法 |
---|---|
IntFunction | R apply(int value) |
DoubleFunction | R apply(double value) |
LongFunction | R apply(long value) |
ToIntFunction | int applyAsInt(T value) |
ToDoubleFunction | double applyAsDouble(T value) |
ToLongFunction | Long applyAsLong(T value) |
DoubleToIntFunction | int applyAsInt(double value) |
DoubleToLongFunction | Long applyAsLong(double value) |
IntToDoubleFunction | double applyAsDouble(int value) |
IntToLongFunction | long applyAsLong(int value) |
LongToDoubleFunction | double applyAsDouble(long value) |
LongToIntFunction | int applyAsInt(long value) |
BiFunction | R apply(T t, U u) |
4.断言型接口
Predicate:断言型接口 单一抽象方法: boolean test(T t);
- 作用:判断对象是否符合某个条件**(传入一个参数,返回一个布尔值)**
- 举例:主要用于流的筛选。给定一个包含若干项的流,Stream接口的filter方法传入一个Predicate并返回一个新的流,它仅包含满足给定谓词的项。
方法 | 描述 |
---|---|
default Predicate and(Predicate<? super T> other) | 接收一个Predicate类型,也就是将传入的条件和当前条件以并且的关系过滤数据。 |
static Predicate isEqual(Object targetRef) | 返回根据 Objects.equals(Object, Object)测试两个参数是否相等的谓词。 |
default Predicate negate() | 返回表示此谓词的逻辑否定的谓词。 |
default Predicate or(Predicate<? super T> other) | 接收一个Predicate类型,将传入的条件和当前的条件以或者的关系过滤数据。 |
boolean test(T t) | 在给定的参数上评估这个谓词 |
public List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> strList = new ArrayList<>();
for(String str:list){
if(pre.test(str)){
strList.add(str);
}
}
return strList;
}
@Test
public void test4(){
List<String> mystr = Arrays.asList("Hello","nihao","lambda","my");
List<String> str1 = filterStr(mystr,(s) -> s.length() > 3);
for (String str:str1 ){
System.out.println(str);
}
}