一、lambda初探
lambda可以是java_8出来新特性,可以使代码更加紧凑以及简洁,增加可读性,下面简单的几个例子我们可以来感受下java lambda的相关魅力
//例子1
//传统写法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("你好世界");
}
}).start();
//增加lambda以后的写法
new Thread(()->System.out.println("你好世界")).start();//省略了内部类,内部抽象方法。
//例子2
ArrayList list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("java");
list.add("python");
list.add("Android");
list.forEach((str)->{
System.out.println(str);
});
//传统写法,注意list.forEach方法是在java 8之后新出来的方法,对应的map.forEach()
list.forEach(new Consumer() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
//优化
list.forEach((str)->System.out.println(str)); //省略了内部类和抽象方法
//再次优化
list.forEach(System.out::println); //省略了相关型参数
//例子3
List personList = Arrays.asList(
new Person("张三",22),
new Person("王五",25),
new Person("赵六",29),
new Person("李二麻子",34),
new Person("小马",18)
);
//传统的排序
Collections.sort(personList, new Comparator() {
@Override
public int compare(Person person, Person t1) {
return person.getAge() - t1.getAge();
}
});
//lambda排序
Collections.sort(personList,(t1,t2)-> t1.getAge() - t2.getAge()); //返回值去掉了{},;和return.
personList.forEach(System.out::println); //进行相应遍历
二、lambda定义与语法
定义 : lambda表达式是函数式编程风格,为了给SAM(Single Abstract Method(单一抽象方法))类型接口变量和形参赋值的一种语法;隐含了匿名内部类创建过程,并替代了原来匿名内部类的对象给函数式接口(SAM接口)的变量或形参赋值的形式。注意该内部类只能有一个方法。
语法格式:(形参列表)->{lambda体}
- (形参列表)就是SAM接口的抽象方法的形参列表。如果类型已知,获取的类型可以推断,数据类型可以省略;形参只有一个可以省略相应形参类型,和形参括号,如果没有参数,那么空括号不能删除。
- {Lambda体} 就是实现SAM接口抽象方法的方法体。如果lambda只有一句,可以省略“{}”,相应的“;”也需要省略,如果没有省略那么“{}”,“;”都不省略;如果返回是一句返回语句,那么"return","{}",";“都可以省略。
- -> 称为Lambda操作符
三、lambda形式
- 无参数,无返回 ()->打印
- 有参数,无返回 (T t...)->打印
- 无参数,有返回 ()-> return
- 有参数,有返回 (T t...) ->return
四、lambda典型接口
1. 消费型接口
接口类 | 抽象方法 | 说明 |
---|---|---|
Consumer |
accept(T t) | 传递一个参数,无返回值 |
BiConsumer |
accept(T t,U u) | 传递两个参数,无返回值 |
DoubleConsumer | accept(double value) | 传递一个double值,无返回值 |
IntConsumer | accept(int value) | 传递一个int值,无返回值 |
LongConsumer | accept(long value) | 传递一个long值,无返回值 |
ObjDoubleConsumer |
accept(T t,double value) | 传递一个对象,和double类型值,无返回值 |
ObjIntConsumer |
accept(T t,double value) | 传递一个对象,和Int类型值,无返回值 |
ObjLongConsumer |
accept(T t,double value) | 传递一个对象,和Long类型值,无返回值 |
总结 : 1. 消费型接口都是以“consumer”单词为结尾
2 . Bi(Binary)开头都是传递两个参数
3. xxConsumer,前面的xx代表形参类型
2.供给型接口
接口类 | 抽象方法 | 说明 |
---|---|---|
Supplier |
T get() | 无参数,有返回值 |
BooleanSupplier | boolean getAsBoolean() | 无参数,返回boolean值 |
DoubleSupplier | double getAsDouble() | 无参数,返回Double值 |
IntSupplier | int getAsInt() | 无参数,返回int值 |
LongSupplier | long getAsLong() | 无参数,返回long值 |
总结 1.供给型接口以“Supplier”单词结尾;2.xxSupplier说明返回xx类型结果 ;3.供给型接口的抽象方法都是无参数的
3. 判断型接口
接口类 | 抽象方法 | 说明 |
---|---|---|
Predicate |
boolean test(T t) | 有一个参数,有返回值 |
BiPredicate |
boolean test(T t,U u) | 有两个参数,有返回值 |
DoublePredicate | boolean test(double value) | 有一个double参数,有返回值 |
IntPredicate | boolean test(int value) | 有一个int 参数,有返回值 |
LongPredicate | boolean test(long value) | 有一个long参数,有返回值 |
总结: 1. 判断型接口以“predicate”结尾 ; 2.判断型接口抽象方法的返回值类型是固定的,是boolean;3xxPredicatte,说明形参是xx类型的
4. 功能型接口
接口类 | 抽象方法 | 说明 |
---|---|---|
Function |
R apply(T t) | 有一个参数,有返回值 |
UnaryOperator |
T apply(T t) | 有一个参数,有返回值,且参数类型和返回值类型一致 |
DoubleFunction |
R apply(double value) | double参数,返回R类型对象 |
IntFunction |
R apply(int value) | int参数,返回R类型对象 |
LongFunction |
R apply(long value) | long 参数,返回R类型对象 |
ToDoubleFunction |
double apply(T t) | T类型对象参数,返回double类型数据 |
ToIntFunction |
int apply(T t) | T类型对象参数,返回int类型数据 |
ToLongFunction |
long apply(T t) | T类型对象参数,返回long类型数据 |
DoubleToIntFunction | int applyAsInt(double value) | double参数,int类型返回数据 |
DoubleToLongFunction | long applyAsInt(double value) | double参数,long类型返回数据 |
IntToDoubleFunction | double applyAsInt(int value) | int 参数,double类型返回数据 |
IntToLongFunction | long applyAsInt(int value) | int 参数,long类型返回数据 |
LongToDoubleFunction | double applyAsInt(long value) | long参数,double类型返回数据 |
LongToIntFunction | int applyAsInt(long value) | long 参数,int类型返回数据 |
DoubleUnaryOperator | double applyasDouble(double orperand) | double参数,double返回数据 |
IntUnaryOperator | int applyasDouble(int orperand) | int 参数,int 返回数据 |
LongUnaryOperator | long applyasDouble(long orperand) | long 参数,long返回数据 |
BiFunction |
R apply(T t,U u) | T,U参数,R返回 |
BinaryOperator |
T apply(T t,T u) | T,T参数,T返回 |
ToDoubleBiFunction |
double applyAsDouble(T t,U u) | T,U参数,double返回 |
ToIntBiFunction |
int applyAsDouble(T t,U u) | T,U参数,int 返回 |
ToLongBiFunction |
long applyAsDouble(T t,U u) | T,U参数,long返回 |
DoubleBinaryOperator | double applyAsDouble(double t1,double t2) | double,double参数,double返回 |
IntBinaryOperator | int applyAsDouble(int t1,int t2) | int ,int 参数,int 返回 |
LongBinaryOperator | long applyAsDouble(longt1,longt2) | long,long参数,long返回 |
总结:
- 以Unary开头,表示一元,泛型的类型只有一个,形参和返回值都是一种类型
- xxFunction,说明形参类别是xx类型
- toxxFunction 说明返回值类型是xx类型
- xxToyyfunction 说明形参的类型是xx类型的,返回值类型yy类型
- xxUnary开头,表示一元,形参和返回都是xx
- Bi开头,表示二元,形参类型是2个
- BinaryOperator既是Bi开头连个形参,又是Oprator结尾,表示形参和返回类型是一致的
- toXXBi开头的,表示返回值类型是xx,并且形参是两个
- xxBinaryOPerator,表示两个形参,又是Operator结尾,表示形参和返回值类型是一样的
五.接口举例
1.消费型接口
ArrayList list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("java");
list.add("python");
list.add("Android");
list.forEach((str)->{
System.out.println(str);
});
//Consumer接口,参数为String类型
list.forEach(new Consumer() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
//用lambda表示
list.forEach(str->{
System.out.println(str);
});
2.供给型接口
//new Supplier get()抽象方法,返回一个double类型数据
Stream stream = Stream.generate(new Supplier() {
@Override
public Double get() {
return Math.random();
}
});
//优化为lambda表达式
Stream.generate(()-> Math.random());
3. 判断型接口
ArrayList personList = new ArrayList<>();
personList.add( new Person("张三",22));
personList.add( new Person("王五",25));
personList.add( new Person("赵六",29));
personList.add(new Person("李二麻子",34));
personList.add( new Person("小马",18));
//Predicate接口,其中参数是一个person对象,返回值为boolean
// personList.removeIf(new Predicate() {
// @Override
// public boolean test(Person person) {
// return person.getAge() > 25;
// }
// });
//优化为lambda样式
personList.removeIf(p->p.getAge() > 25);
personList.forEach(System.out::println);
返回结果:
Person{name='张三', age=22}
Person{name='王五', age=25}
Person{name='小马', age=18}
4. 功能型接口
//例子1.
ArrayList personList = new ArrayList<>();
personList.add( new Person("张三",22));
personList.add( new Person("王五",25));
personList.add( new Person("赵六",29));
personList.add(new Person("李二麻子",34));
personList.add( new Person("小马",18));
//功能型接口,参数为person,返回为person
personList.replaceAll(new UnaryOperator() {
@Override
public Person apply(Person person) {
if(person.getAge() > 25)
person.setAge(30);
return person;
}
});
personList.forEach(System.out::println);
打印结果:
Person{name='张三', age=22}
Person{name='王五', age=25}
Person{name='赵六', age=30}
Person{name='李二麻子', age=30}
Person{name='小马', age=18}
//例2
HashMap map = new HashMap<>();
map.put("张三",new Person("张三",22));
map.put("王五",new Person("王五",25));
map.put("赵六",new Person("赵六",29));
map.put("李二麻子",new Person("李二麻子",34) );
map.put("小马",new Person("小马",18) );
//参数为string,person,返回为person
map.replaceAll(new BiFunction() {
@Override
public Person apply(String s, Person person) {
if(person.getAge() > 25)
person.setAge(30);
return person;
}
});
map.forEach((key,person)->{
System.out.println(key + "::" + person.toString());
});
打印结果:
张三::Person{name='张三', age=22}
李二麻子::Person{name='李二麻子', age=30}
小马::Person{name='小马', age=18}
王五::Person{name='王五', age=25}
赵六::Person{name='赵六', age=30}
六.Lambda方法引用
方法引用使用“::”双冒号组成操作符来指定方法。方法引用后,参数会自动传递。
-
类的构造器引用 ArrayList::new ,String[] ::new
Arrays.asList("a","b","c").stream().toArray(String[]::new); //转变为数组
-
类的静态方法引用 Stirng::valueOf,Integer::value of,
Stream.of("1", "2","3").map(Integer::valueOf).forEach(System.out::println);
-
类的实例方法应用 String::length,Person::getName
Stream.of(new Person("张三",22), new Person("王五",25),new Person("赵六",29)) .map(Person::getAge).forEach(System.out::println);
对象的实例方法应用Sting::length,person::getName;
七.自定义SAM接口
声明接口,只能包含一个抽象方法,必须给这个接口添加@FunctionalInterface
@FunctionalInterface
public interface IntCalc {
int cal(int a,int b);
}
public static void getProduct(int a,int b,IntCalc tools){
int result = tools.cal(a,b);
System.out.println("结果:" +result);
}
//调用该方法,其中方法该接口作为参数传入,相当于传入了该操作方法体。
getProduct(1,2,(a,b) -> a+ b); //
打印结果:
结果:3
八.结语
本文是根据尚硅谷柴林燕老师讲授整理而来,同时参考Java基础系列-Lambda