文章目录
1.什么是lambda表达式
Lambda是JAVA8添加的一个新的特性。说白了,Lambda就是一个匿名函数。
2.为什么要使用lambda表达式
使用Lambda表达式可以对一个接口进行非常简洁的实现。
3.lambda对接口的要求
虽然可以使用Lambda表达式对某些接口进行简单的实现,但是并不是所有的接口都可以用Lambda表达式来实现。要求接口中定义的必须要实现的抽象方法只能是一个。
@FunctionalInterface
修饰函数式接口的。接口中的抽象方法只有一个。
//这个注解是用来限制下面这个接口只能有一个抽象方法
@FunctionalInterface
interface Comparator{
int compare(int a,int b);
}
class MyComparator implements Comparator{
@Override
public int compare(int a, int b) {
// TODO Auto-generated method stub
return a-b;
}
}
public class Test1 {
public static void main(String[] args) {
//1 .使用接口实现类
Comparator comparator1=new MyComparator();
//2.使用匿名内部类实现
Comparator comparator2=new Comparator() {
@Override
public int compare(int a, int b) {
// TODO Auto-generated method stub
return a-b;
}
};
//3.使用lambda表达式实现接口
Comparator comparator3=(a,b)->a-b;
}
}
4.lambda基础语法
//无返回值,无参数
@FunctionalInterface
public interface LambdaNoneReturnNoneParameter {
void test();
}
//无返回值,单个参数
@FunctionalInterface
public interface LambdaNoneReturnSingleParameter {
void test(int n);
}
//无返回值,多个参数
@FunctionalInterface
public interface LambdaNoneReturnMutipleParameter {
void test(int m,int n);
}
//单个返回值,无参数
@FunctionalInterface
public interface LambdaSingleReturnNoneParameter {
int test();
}
//单个返回值,单个参数
@FunctionalInterface
public interface LambdaSingleReturnSingleParameter {
int test(int n);
}
//单个返回值,多个参数
@FunctionalInterface
public interface LambdaSingleReturnMultipleParameter {
int test(int a,int b);
}
public class Syntax1 {
public static void main(String[] args) {
//1.lambda表达式的基础语法
//lambda是一个匿名函数
//参数列表 方法体
//():用来描述参数列表
//{}:用来描述方法体
//->lambda运算符,读作goes to
//无参无返回
LambdaNoneReturnNoneParameter lambda1=()->{
System.out.println("hello world");
};
lambda1.test();//hello world
//无返回值,单个参数
LambdaNoneReturnSingleParameter lambda2=(int a)->{
System.out.println(a);
};
lambda2.test(10);//10
//无返回值,多个参数
LambdaNoneReturnMutipleParameter lambda3=(int a,int b)->{
System.out.println(a+" "+b);
};
lambda3.test(2, 3);//2 3
//有返回值,无参数
LambdaSingleReturnNoneParameter lambda4=()->{
return 1;
};
System.out.println(lambda4.test());//1
//有返回值,一个参数
LambdaSingleReturnSingleParameter lambda5=(int a)->{
return a;
};
System.out.println(lambda5.test(5));//5
//有返回值,多个参数
LambdaSingleReturnMultipleParameter lambda6=(int a,int b)->{
return a+b;
};
System.out.println(lambda6.test(2, 3));//5
}
}
5.lambda表达式语法精简
public class Syntax2 {
public static void main(String[] args) {
//语法精简
//1.参数
//由于在接口的抽象方法中,已经定义了参数的数量和类型,所以在lambda表达式中,参数的类型可以忽略
//备注:如果需要省略参数类型,则每一个参数类型都要省略
LambdaNoneReturnMutipleParameter lambda1=(a,b)->{
System.out.println(a+b);
};
lambda1.test(2,3);//5
//2.参数小括号
//如果参数列表中,参数的数量只有一个,此时小括号可以省略
LambdaNoneReturnSingleParameter lambda2=a->{
System.out.println(a);
};
lambda2.test(3);//3
//3.方法大括号
//如果方法体重只有一条语句,那么大括号可以省略
LambdaNoneReturnSingleParameter lambda3=a->System.out.println(a);
lambda3.test(4);//4
//4.如果方法体中唯一一条语句是一个返回语句,则在省略大括号的同时,也必须省略return
LambdaSingleReturnNoneParameter lambda4=()->10;
System.out.println(lambda4.test());//10
LambdaSingleReturnMultipleParameter lambda5=(a,b)->a+b;
System.out.println(lambda5.test(2, 3));//5
}
}
6.lambda语法进阶
普通方法引用
public class Syntax3 {
public static int change(int a){
return a*2;
}
public static void main(String[] args) {
//方法引用:
//可以快速的将一个lambda表达式的实现指向一个已经实现的方法
//语法:方法的隶属者::方法名
//注意:
//1.参数数量和类型一定要和接口中定义的方法一致
//2.返回值的类型一定要和接口中定义的类型一致
LambdaSingleReturnSingleParameter lambda1=a->change(a);
System.out.println(lambda1.test(1));//2
//方法引用:引用了change方法实现
LambdaSingleReturnSingleParameter lambda2=Syntax3::change;
System.out.println(lambda2.test(3));//6
}
}
构造方法引用
public class Person {
public String name;
public int age;
public Person() {
super();
System.out.println("无参方法执行了");
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
System.out.println("有参方法执行了");
}
}
//需求:
interface PersonCreate{
Person getPerson();
}
interface PersonCreate2{
Person getPerson(String name,int age);
}
public class Syntax4 {
public static void main(String[] args) {
PersonCreate create1=()->{
return new Person();
};
//可以再次精简
PersonCreate create2=()->new Person();
//构造方法的引用
PersonCreate create3=Person::new;
Person a=create3.getPerson();//无参方法执行了
PersonCreate2 create4=Person::new;
Person b=create4.getPerson("king", 12);//有参方法执行了
}
}
案例
集合排序
public class Exercise1 {
//集合排序
//ArrayList<>
public static void main(String[] args) {
//需求:已知在一个ArrayList中有若干个person对象,将这些person对象按照年龄进行降序排序
ArrayList<Person> list=new ArrayList<Person>();
list.add(new Person("aa",12));
list.add(new Person("bb",44));
list.add(new Person("cc",52));
//降序排序
list.sort((o1,o2)->o2.age-o1.age);
System.out.println(list);
//[Person [name=cc, age=52], Person [name=bb, age=44], Person [name=aa, age=12]]
}
}
TreeSet
public class Exercise2 {
public static void main(String[] args) {
//使用lambda表达式实现comparator接口,并实例化对象
//实现降序
TreeSet<Person> set=new TreeSet<>((o1,o2)->o2.age-o1.age);
set.add(new Person("aa",12));
set.add(new Person("bb",44));
set.add(new Person("cc",52));
}
}
forEach
public class Exercise3 {
public static void main(String[] args) {
//集合遍历
ArrayList<Integer> list=new ArrayList<>();
Collections.addAll(list, 1,2,3,4,5,6);
//将集合中的每一个元素都带入到方法accept中
list.forEach(System.out::println);
/*输出:
* 1
* 2
* 3
* 4
* 5
* 6
*/
//输出集合中所有的偶数
list.forEach(a->{
if(a%2==0)
System.out.println(a);
});
}
}
removeif
public class Exercise4 {
public static void main(String[] args) {
//需求:删除集合中满足条件的元素
ArrayList<Person> list=new ArrayList<Person>();
list.add(new Person("aa",12));
list.add(new Person("bb",44));
list.add(new Person("cc",52));
//删除年龄>45岁的人
//lambda表达式实现
//将集合中的每一个元素都带入到test方法中,如果返回值是true,则删除这个元素
list.removeIf(a->a.age>45);
System.out.println(list);
//[Person [name=aa, age=12], Person [name=bb, age=44]]
}
}
线程实例化
public class Exercise5 {
public static void main(String[] args) {
//需求:开辟一条线程。做一个数字的输出
Thread t=new Thread(()->{
for(int i=0;i<10;i++)
System.out.println(i);
});
t.start();
}
}
7.系统内置函数式接口
//系统内置的一些函数式接口
//Predicate<T>:参数了返回值boolean
//IntPredicate int->boolean
//LongPredicate long->boolean
//DoublePredicate double->boolean
//Consumer<T>:参数T返回值void
//IntConsumer int->void
//LongConsumer long->void
//DoubleConsumer double->void
//Function<T,R>:参数了返回值R
//IntFunction<R>int->R
//LongFunction<R>long->R
//DoubleFunction<R> double->R//IntTolongFunction int->long
//IntToDoubleFunction int->double
//LongToIntFunction long->int
//LongToDoubleFunction long->double
//DoubleToIntFunction doublt->int
//DoubleTolongFunction double->long
//Supplier<T>:参数无返回值T
//UnaryOperator<T>:参数了返回值T
//BinaryOperator<T>:参数T,T返回值T//BiFunction<T,U,R>:参数T,U返回值R
//BiPredicate<T,U>:参数T,U返回值boolean
//BiConsumer<T,U>:参数T,U返回值void
//Predicate<T>、Consumer<T>、Function<T,R>、Supplier<T>,比较常用
常见类型:
注意:在这些内置系统函数中,最多只有两个参数,如果有返回值,最后一个参数是返回值类型,如果入参多于两个,需要通过接口来实现lambda表达式
public class 常用内置函数式接口 {
static void 例子(){
//无入参,无返回
Runnable r=()->System.out.println("11");
r.run();//11
//无参,有返回
Supplier<Float> s=()->200f+300f;
System.out.println(s.get());//500.0
//1参,无返回
Consumer<Date> c=(d)->System.out.println("当前时间:"+d.toString());
c.accept(new Date());//当前时间:Thu Jun 11 14:34:09 CST 2020
//1参,有返回
Function<StringBuffer,String> f=sb->sb.reverse().toString();
System.out.println(f.apply(new StringBuffer("abcd")));//dcba
//2参,无返回
BiConsumer<String,Integer> bc=(str,n)->{
String ss="";
for(int i=0;i<n;i++){
ss+=str;
}
System.out.println(ss);
};
bc.accept("abc", 3);//abcabcabc
//2参,有返回
BiFunction<Integer,Integer,String> bif=(i,j)->i+""+j;
System.out.println(bif.apply(1, 2));//12
}
public static void main(String[] args) {
例子();
}
}
8.流式运算
增强java.util下集合框架的功能。装饰者模式的思想(套一个新的接口马甲,功能更强-各种操作、支持链式风格、支持多种内置的lambda函数接口作为对象)。流式算法。视图。
Stream是处理数组和集合的API,Stream具有以下特点:
• 不是数据结构,没有内部存储
• 不支持索引访问
• 延迟计算
• 支持过滤,查找,转换,汇总等操作
首先需要弄清楚lambda的两个操作类型:中间操作
和终止操作
。
下面通过一个demo来认识下这个过程。
Stream st=Arrays.asList(1,2,3,4,5).stream().filter(x->{
System.out.print(x);
return x>3;
});
当我们执行这段代码的时候,发现并没有任何输出,这是因为lambda表达式需要一个终止操作来完成最后的动作。 我们修改代码:
Stream st=Arrays.asList(1,2,3,4,5).stream().filter(x->{
System.out.print(x);
return x>3;
});
st.forEach(t-> System.out.print(t));
对应的输出结果是:
1234455
为什么会有这个输出呢?因为在filter函数的时候并没有真正的执行,在forEach的时候才开始执行整个lambda表达式,所以当执行到4的时候,filter输出之后,forEach也执行了,最终结果是1234455
对于Java中的lambda表达式的操作,可以归类和整理如下:
中间操作:链式风格
。
• 过滤 filter
• 去重 distinct
• 排序 sorted
• 截取 limit、skip
• 转换 map/flatMap
• 其他 peek
终止操作:无法用链式风格继续写。
• 循环 forEach
• 计算 min、max、count、 average
• 匹配 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny
• 汇聚 reduce
• 收集器 toArray collect
举例:
public class Car {
private String band;
private float price;
private float toSpeed;
public String getBand() {
return band;
}
public void setBand(String band) {
this.band = band;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public float getToSpeed() {
return toSpeed;
}
public void setToSpeed(float toSpeed) {
this.toSpeed = toSpeed;
}
public Car(String band, float price, float toSpeed) {
super();
this.band = band;
this.price = price;
this.toSpeed = toSpeed;
}
@Override
public String toString() {
return "Car [band=" + band + ", price=" + price + ", toSpeed=" + toSpeed + "]";
}
}
public class CarDemo {
static void test(Car[] car,HashMap map){
//将数组转成集合
List<Car> list=Arrays.asList(car);
//过滤价格和速度为负数的车,并且按照toSpeed逆序排序,提取小集合,去重复
Stream st=list.stream().filter((ss)->ss.getPrice()>0&&ss.getToSpeed()>0).sorted((o1,o2)->(int)(o2.getToSpeed()-o1.getToSpeed())).map(s->s.getBand()).distinct();
st.forEach(System.out::println);
Set<Integer> set=map.keySet();
Stream st1=set.stream().sorted((o1,o2)->o1-o2).limit(3);
st1.forEach(s->{
System.out.println("第"+s+"名:"+map.get(s));
});
}
}
public class CarTest {
public static void main(String[] args) {
HashMap<Integer,Car> map=new HashMap<>();
Car[] car=new Car[5];
car[0]=new Car("宝马",230,200);
car[1]=new Car("奔驰",246,456);
car[2]=new Car("红旗",300,678);
car[3]=new Car("丰田",500,987);
car[4]=new Car("宝马",100,134);
map.put(2, car[0]);
map.put(1, car[1]);
map.put(3, car[2]);
map.put(4, car[3]);
map.put(7, car[4]);
CarDemo.test(car,map);
}
}
结果:
丰田
红旗
奔驰
宝马
第1名:Car [band=奔驰, price=246.0, toSpeed=456.0]
第2名:Car [band=宝马, price=230.0, toSpeed=200.0]
第3名:Car [band=红旗, price=300.0, toSpeed=678.0]
9.闭包
public class ClosureDemo2 {
public static void main(String[] args) {
//在闭包中使用的变量一定是常量
int a=10;
Consumer<Integer> c=b->{
System.out.println(b);
};
c.accept(a);//10
}
}