🍤Lambda表达式
- Lambda表达式练习题
- JDK提供的四大函数接口
- 消费型:Consumer<T> ----------------void accept(T t)有参数无返回值
- 函数型:Function<T,R>-----------------R apply(T t)有一个参数,一个返回值
- 段言型:Predicate<T>-------------------boolean test(T t)一个参数返回一个布尔型
- 供给型:Supplier<T>---------------------T get()没有参数返回一个值
- 方法引用
- 构造器引用
- 数组引用
- JDK8之后提供的Stream API
一、Lambda表达式练习
1、题目一:调用Collections.sort()方法,通过定值排序比较两个Employee(先按年龄比,年龄相同按姓名比),使用Lambda作为参数传递
分析:
- 定制排序:指自定义比较器|定制排序
自然排序:内部比较器|自然排序 - 先比较年龄,年龄相同才比较姓名
public class Lambda02 {
public static void main(String[] args) {
List<Emp> ls=new ArrayList<>();
ls.add(new Emp(20,"张三"));
ls.add(new Emp(18,"李四"));
ls.add(new Emp(18,"小明"));
ls.add(new Emp(19,"王五"));
Collections.sort(ls,(x,y)->{
if(x.getAge()==y.getAge()){
return x.getName().compareTo(y.getName());
}
return x.getAge()-y.getAge();
});
System.out.println(ls);
}
}
class Emp{
public Emp() {
}
@Override
public String toString() {
return "Emp{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Emp(int age, String name) {
this.age = age;
this.name = name;
}
private int age;
private String name;
}
2、题目二:
- 声明函数式接口,接口中声明抽象方法,public String getValue(String str)
- 声明类 TestLambda,类中编写方法使用接口作为参数,讲一个字符串转成大写,并作为方法的返回值
- 再将一个字符串的第2个和第4个索引位置进行截取子串
public class Lambda03 {
public static void main(String[] args) {
String uu=StringMethod("sertishdjscds",(x)->{
//return x.toUpperCase();
return x.substring(2,4);
});
System.out.println(uu);
}
public static String StringMethod(String s,Stringss ss){
return ss.getValue(s);
}
}
interface Stringss{
String getValue(String str);
}
3、题目三
- 声明一个带两个泛型的函数式接口,发型类型为<T,R> T为参数,R为返回值。
- 接口中声明对应抽象方法。
- 在TestLambda类中声明方法,参数三个,两个long类型的参数,接口作为参数,接口实现中计算两个long型参数的和。
- 再计算两个long型参数的乘积。
public class Lambda04 {
public static void main(String[] args) {
long num=toSum(1000L,500L,(x,y)->{
return x+y;
});
System.out.println(num);
TestLam<Long,Long> tl=new TestLam<Long, Long>() {
@Override
public Long sum(Long x, Long y) {
return null;
}
};
}
public static long toSum(long l1,long l2,TestLam<Long,Long> tl){
return tl.sum(l1,l2);
}
}
interface TestLam<R,U>{
U sum(R x,R y);
}
二、JDK提供的四大函数接口
代码演示:
public class Lambda001 {
public static void main(String[] args) {
//消费性
shop(1000,(monery)->{
System.out.println("冲游戏皮肤花费:"+monery);
});
//函数型
System.out.println(Fun(2, num -> num << 2));
//段言型
System.out.println(isTrue(10, num -> {
if (num >= 10) {
return true;
}
return false;
}));
//供给型
System.out.println(get(() -> {
return (int) (Math.random() * 10 + 1);
}));
}
//消费型
public static void shop(int x, Consumer<Integer> con){
con.accept(x);
}
//函数xing
public static int Fun(int num, Function<Integer,Integer> sum){
return sum.apply(num);
}
//段言型
public static boolean isTrue(int i, Predicate<Integer> pi){
return pi.test(i);
}
//供给型
public static int get(Supplier<Integer> sup){
return sup.get();
}
}
三、方法引用
-
方法引用就是对Lambda表达式的简化
要求:1)lambda体的实现,是通过调用|引用另外一个方法实现的 2)引用的方法的参数列表与返回值要求与要重写的抽象方法的参数列表与返回值保持一致,自动匹配 3)如果返回值匹配,但是参数列表不完全匹配,可以考虑是否满足第三种情况: 使用 类名::成员方法名 简化 如果参数列表只有一个,这个参数作为内部调用方法的对象存在 如果参数列表存在多个,第一个参数作为内部调用方法的对象,第二个参数开始自动匹配内部所引用方法的参数列表
-
使用方式:
-
对象::成员方法名 :(对象真实存在)
-
类名::静态方法名
-
类名::成员方法名 :( 对象自动匹配,对象是lambda的参数提供的)
-
① 、对象::成员方法名
public class Lambda002 {
public static void main(String[] args) {
print();
}
public static void print(){
//平时写法
// Consumer<Integer> con=new Consumer() {
// @Override
// public void accept(Object o) {
//
// }
// };
//简化
Consumer c=x->{
System.out.println(x);
};
//println是PringStream的成员方法
PrintStream p=System.out;
Consumer cj=x->{
p.println(x);
};
cj=p::println;
cj.accept("niubi");
c.accept("好家伙");
List<Integer> li= Arrays.asList(1,2,3,4,5);
li.forEach(System.out::print);
}
}
②、类名::静态方法名
public class Lambda003 {
public static void main(String[] args) {
max();
}
public static void max(){
BiFunction<Integer,Integer,Integer> bi=new BiFunction<>() {
@Override
public Integer apply(Integer o1, Integer o2) {
return Math.max(o1,o2);
}
};
//简化
bi=(x,y)->{return Math.max(x,y);};
System.out.println(bi.apply(100,300));
//再次简化
bi=Math::max;
System.out.println(bi.apply(100,500));
}
}
③、类名::成员方法
public class Lambda004 {
public static void main(String[] args) {
test();
}
public static void test(){
BiPredicate<String,String> bs=new BiPredicate<String, String>() {
@Override
public boolean test(String s, String s2) {
return s.equals(s2);
}
};
System.out.println(bs.test("abc", "abc"));//true
//简化
bs=(x,y)->{
return x.equals(y) ;
};
System.out.println(bs.test("iii", "iii"));//true
//简化
bs=String::equals;
System.out.println(bs.test("1234", "123"));//false
}
}
四、构造器引用
- 数据类型::new
- 要求: lambda参数列表与构造器的参数列表保持一致
public class Lambda005 {
public static void main(String[] args) {
//构造器引用
demo();
}
public static void demo(){
Function<String,String> fs=new Function<String, String>() {
@Override
public String apply(String s) {
return new String(s);
}
};
System.out.println(fs.apply("xiaoxiaoxiao"));
//简化
fs=(x)->{return new String(x);};
fs.apply("abcdefg");
//简化
fs=x->new String(x);
fs.apply("小明");
//简化
fs=String::new;
fs.apply("完!!!!");
}
}
五、 数组引用
- 类型::new
//数组 引用
Function<Integer,int[]> sup2 = (i)->new int[i];
sup2 = int[]::new;
System.out.println(sup2.apply(3));
System.out.println(Arrays.toString(sup2.apply(3)));
六、JDK8之后提供的Stream API
Stream :
数据的渠道,用来操作由数据源(数组,集合)产生元素序列
数组|集合关注数据的存储,Stream关注的是对数据的计算
特点:
1.Stream本身不能存储数据
2.Stream不会修改原对象|数据源中的数据,在每次进行流式操作后会返回一个持有结果的新的流
3.惰性加载|延迟执行: 在进行stream操作时候不会马上执行,会在获取结果时一起执行
4.流式一次性的流,流是不能重复使用,因为这个流已经被使用消费了
创建流:
1. Collection中的成员stream()
2. Arrays.stream(数组)
3.Stream.of(数据)
代码演示;
public class Stream001 {
public static void main(String[] args) {
// 1. Collection中的成员stream()
List<Integer> list=List.of(1,2,3,4,5,6);
Stream<Integer> st=list.stream();
System.out.println(list.parallelStream());
//2. Arrays.stream(数组)
String[] arr={"111","222","333"};
Stream st1= Arrays.stream(arr);
System.out.println(st1);
//3.Stream.of(数据)
Stream<String> ss=Stream.of("123","234","456");
System.out.println(ss);
}
}
**使用Stream的过程:**
1.获取流
2.一系列流式的中间操作 (返回持有结果的新的流)
3.终止行为(返回真实结果)
中间操作 : 筛选与切片
filter: 过滤
limit:限制从流中获得前n个数据
distinct:去重
skip:跳过前n个数据
代码演示:
public class Class002_Stream {
public static void main(String[] args) {
List<Employee> list = List.of(
new Employee(1001,"zhangsan",18,20000),
new Employee(1002,"lisi",25,18000),
new Employee(1003,"wangwu",30,15000),
new Employee(1004,"zhaoliu",28,10000),
new Employee(1004,"zhaoliu2",28,10000),
new Employee(1004,"zhaoliu",28,10000)
);
//1.获取流
Stream<Employee> stream = list.stream();
//2.中间操作
stream = stream.filter(employee ->employee.getAge()>18)
.distinct()/*要求重写hashCode与equals*/
.limit(3)
.skip(1);
//3.终止行为
stream.forEach(System.out::println);
}
}