两个参数Lambda 表达式
两个参数的 Lambda 表达式使用,当函数体/方法体中只有一个return语句时,return和大括号都可以省略。
java
package com.wlx.day17;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TreeMap;
public class LambdaTest
{
/**
* 练习:
* 使用Lambda表达式的方式,分别对List集合进行倒序排序。
*/
@Test
public void listDemo()
{
List<Integer> list = new ArrayList<>();
list.add(23);
list.add(2);
list.add(13);
list.add(3);
list.add(26);
// list.sort((o1, o2) -> {return o1 > o2 ? -1:1;});
//当函数体/方法体中只有一个return语句时,return和大括号都可以省略
list.sort((o1, o2) -> o1 > o2 ? -1:1);
/*System.out.println(list);*/
/*Collections.sort(list,(o1, o2) -> {
if(o1 > o2)
{
return -1;
}
else if(o1 < o2)
{
return 1;
}
else
{
return 0;
}
});*/
//只有改变o1和o2的顺序即可改变倒序和正序
// Collections.sort(list,(o1,o2)->{return Integer.compare(o2,o1);});
//当函数体/方法体中只有一个return语句时,return和大括号都可以省略
Collections.sort(list,(o1,o2)->Integer.compare(o2,o1));
System.out.println(list);
}
/**
* 练习:
* 使用Lambda表达式的方式,分别对Map集合进行倒序排序。
*/
@Test
public void mapDemo()
{
// TreeMap<Integer,String> tm = new TreeMap<>((o1,o2)->Integer.compare(o2,o1));
TreeMap<Integer,String> tm = new TreeMap<>((o1, o2) -> {
if(o1 > o2)
{
return -1;
}
else if(o1 < o2)
{
return 1;
}
else
{
return 0;
}
});
tm.put(23,"tom");
tm.put(2,"jim");
tm.put(13,"tim");
tm.put(26,"lilei");
tm.put(36,"hanmm");
tm.put(62,"lucy");
System.out.println(tm);
}
}
语法糖
Lambda 方法引用,Lambda 表达式的语法糖。
格式:
类 :: 要引用的方法
函数式接口
java
package com.wlx.day17;
@FunctionalInterface
public interface FntInterface2
{
public int bjq(Integer a,Integer b);
}
自定义类
java
package com.wlx.day17;
public class MyInteger
{
public static int myCompare(Integer c,Integer d)
{
return c + d;
}
}
Lambda 表达式语法糖实现
java
@Test
public void test1()
{
FntInterface2 fnt2 = (a,b) -> Integer.compare(a,b);
//调用fnt2对象中的bjq()方法,具体返回的结果是根据Lambda表达式的计算结果返回
// System.out.println(fnt2.bjq(12, 12));
FntInterface2 ft = Integer :: compare;
//调用ft对象中的bjq()方法,具体返回的结果是根据Lambda表达式的计算结果返回
// System.out.println(ft.bjq(12, 12));
FntInterface2 fn = (a,b) -> MyInteger.myCompare(a,b);
/*
调用fn对象中的bjq()方法,具体返回的结果是根据Lambda表达式的计算结果返回
即返回myCompare()方法的结果
*/
System.out.println(fn.bjq(2, 3));
/*
调用nt对象中的bjq()方法,具体返回的结果是根据Lambda表达式的计算结果返回
即返回myCompare()方法的结果
*/
FntInterface2 nt = MyInteger::myCompare;
System.out.println(nt.bjq(3, 3));
}
方法引用
方法引用其实就是 Lambda 表达式的一个语法糖。
要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致。
操作符: :: , 使用该操作符将类或对象与方法分隔开来。
格式一:
对象名 :: 实例方法名
格式二:
类名 :: 静态方法名
格式三:
类名 :: 实例方法名
1.1、对象名 :: 实例方法名
方法引用使用的要求: 要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同。
函数式接口 1
java
package com.wlx.day17;
@FunctionalInterface
public interface MyLambdaInterface
{
public int compre(String s,String t);
}
函数式接口 2
java
package com.wlx.day17;
public interface MyLambdaFace
{
public void shuchu(String str);
}
自定义类
java
package com.wlx.day17;
public class MyLambdaClass
{
public int copa(String s,String t)
{
return s.length()+t.length();
}
}
测试方法
java
@Test
public void test2()
{
MyLambdaClass mlc = new MyLambdaClass();
MyLambdaInterface mli = mlc :: copa;
/*
调用函数式接口中的compre(),并传递参数,返回mlc对象对应的copa()
计算以后的结果
*/
System.out.println(mli.compre("hello","world"));
}
@Test
public void test3()
{
PrintStream ps = System.out;
MyLambdaFace mlf = ps :: println;
/*
调用函数式接口中的shuchu(),并传递参数,输出结果是ps对象对应的println()
处理以后的结果
*/
mlf.shuchu("hello System.out.println");
}
优化支持多种类型
接口:
java
package com.wlx.day17;
public interface MyLambdaFace<T>
{
public void shuchu(T t);
}
测试类
java
@Test
public void test3()
{
PrintStream ps = System.out;
MyLambdaFace<Object> mlf = ps :: println;
/*
调用函数式接口中的shuchu(),并传递参数,输出结果是ps对象对应的println()
处理以后的结果
*/
mlf.shuchu("hello System.out.println");
mlf.shuchu(123);
mlf.shuchu(new Users());
//使用Oracle提供的函数式接口
Consumer con = ps :: println;
con.accept("hello Consumer---");
con.accept(321);
con.accept(new Users());
}
1.2、类::静态方法名
抽象方法和静态方法参数列表和返回值类型一样时使用。
测试方法
java
@Test
public void test4()
{
/*
使用Oracle提供的函数式接口Function,返回的结果同样是
myCompare2()方法返回的结果
*/
Function<Integer,Integer> ft = MyInteger::myCompare2;
Integer it = ft.apply(123);
System.out.println(it);
}
使用 Oracle 提供的 Function 接口
自定义方法
java
public static String hqString(Users users)
{
return users.getUsername()+ users.getUserpwd();
}
测试方法
java
@Test
public void test5()
{
Users users = new Users(1,"tom","tom123",23,"男");
Function<Users,String> fnt = MyInteger::hqString;
//打印获取hqString()方法返回的结果值
System.out.println(fnt.apply(users));
}
1.3、类::实例方法名
自定义函数式接口时,第一个形参要和语法糖中的类名一致,后面的形参用于传递给调用的实例方法,并且函数式接口中的形参个数和类名中方法形参个数始终保持一个形参的相差,接口形参大于类中形参个数。
自定义函数式接口
java
package com.wlx.day17;
public interface MyFunction
{
public String getUser(Users users,String s);
}
自定义类
java
package com.wlx.day17;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Users
{
private Integer uid;
private String username;
private String userpwd;
private Integer userage;
private String usersex;
public String hqUsers()
{
return username+"\t"+userpwd;
}
public String hqUsers2(String str)
{
return username+"\t"+userpwd+"\t"+str;
}
}
测试方法
java
@Test
public void test6()
{
com.wlx.day17.Users users = new com.wlx.day17.Users(1,"jim","jim123",23,"男");
Function<com.wlx.day17.Users,String> fnt = com.wlx.day17.Users::hqUsers;
//打印获取hqUsers()方法返回的结果值
//System.out.println(fnt.apply(users));
/*Comparator<String> com = String::compareTo;
System.out.println(com.compare("hello","hello"));*/
MyFunction mf = com.wlx.day17.Users::hqUsers2;
//第一个参数users和Users类型一致,字符串"haha"传递给hqUsers2(),
// 最终结果返回的是hqUsers2()方法返回的结果
System.out.println(mf.getUser(users, "haha"));
}
构造方法引用
构造方法引用和普通方法引用类似,函数式接口的抽象方法的形参列表和构造方法的形参列表一致;抽象方法的返回值类型即为构造方法所属的类的类型。
函数式接口的泛型,最后一个泛型类型是构造方法所属的类型,前面的泛型都是构造方法的形参类型,按照顺序排列接口。
格式:
类名 :: new
java
/**
* 无参数的构造方法的使用
*/
@Test
public void test7()
{
//使用Oracle提供的函数式接口
Supplier<Users> sup = new Supplier<Users>() {
@Override
public Users get() {
return new Users();
}
};
System.out.println("---"+sup.get());
//Lambda表达式使用
Supplier<Users> supp = () -> new Users();
System.out.println("==="+supp.get());
//语法糖使用
Supplier<Users> suppli = Users::new;
System.out.println("***"+suppli.get());
}
/**
* 有一个参数的构造方法调用
*/
@Test
public void test8()
{
//该函数式接口的泛型,第二个泛型类型是构造方法对应类的类型,
// 第一个泛型类型是为构造方法传递参数的类型
Function<String, com.wlx.day17.Users> fnt = com.wlx.day17.Users::new;
//此处调用Function接口中的apply(),参数是给构造方法传递参数,返回的值是Users对象
System.out.println(fnt.apply("tomjimlilei"));
}
自定义函数式接口---无泛型
java
package com.wlx.day17;
public interface MyFunction2
{
public Users hqUsers6(Integer uid,String username,String userpwd,Integer userage,String usersex);
}
测试方法
java
/**
* 无泛型的方式
*/
@Test
public void test9()
{
MyFunction2 mf = com.wlx.day17.Users::new;
System.out.println(mf.hqUsers6(16, "shenteng", "st123", 23, "男"));
}
自定义函数式接口---有泛型
java
package com.wlx.day17;
/**
*
* @param <E1>构造方法第一个参数类型
* @param <E2>构造方法第二个参数类型
* @param <E3>构造方法第三个参数类型
* @param <E4>构造方法第四个参数类型
* @param <E5>构造方法第五个参数类型
* @param <T>最后一个泛型是构造方法所属的类型
*/
public interface MyFunction3<E1,E2,E3,E4,E5,T>
{
public T hqUsers6(E1 uid,E2 username,E3 userpwd,E4 userage,E5 usersex);
}
测试方法
java
/**
* 有泛型
*/
@Test
public void test10()
{
MyFunction3<Integer,String,String,Integer,String,com.wlx.day17.Users> mf = com.wlx.day17.Users::new;
System.out.println(mf.hqUsers6(16, "shenteng", "st123", 23, "男"));
}
数组的引用
数组的引用和构造方法一样。
java
@Test
public void test11()
{
//Lambda表达式使用
Function<Integer,String[]> ft = length -> new String[length];
String[] st = ft.apply(3);
st[0] = "tom";
st[1] = "jim";
st[2] = "lilei";
System.out.println(Arrays.toString(st));
//语法糖的使用
Function<Integer,String[]> fnt = String[]::new;
String[] str = ft.apply(3);
str[0] = "hanmm";
str[1] = "lihua";
str[2] = "lucy";
System.out.println(Arrays.toString(str));
}
Stream
集合关注的是数据的存储,与内存打交道。
Stream 关注的是对数据的运算,与 CPU 打交道。
注意:
1、Stream 自己不会存储元素
2、Stream 不会改变源对象,相反它们会返回一个持有结果的新 Stream。
3、Stream 操作是延迟执行的,这意味着他们会等到需要结果的时候才运行。
1.1、Stream 执行流程
1、Stream 的实例化,即创建 Stream
一个数据源(集合,数组),获取一个流。
2、一系列的中间操作。
中间操作链,对数据源的数据进行处理。
3、终止操作。
一旦执行终止操作,就执行中间操作链,并产生结果,之后,不会在被使用,如果要再次使用,必须重新创建对象。
1.2、创建 Stream
1.2.1、通过 Collection 创建对象
创建 Stream 方式一:
JDK8 中的 Collection 接口。
java
@Test
public void test1()
{
List<Users> list = new ArrayList<>();
//创建Stream对象
Stream<Users> st = list.stream();
//创建Stream对象
Stream<Users> tem = list.parallelStream();
}
1.2.3、通过 Stream 的 of()创建
创建 Stream 方式三:
可以调用 Stream 类的静态方法 of(),通过显示值创建一个 Stream,它可以接收任意数量的参数。
java
public void test3()
{
Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
}
1.2.4、创建 Stream 的 iterate()和 generate()
Stream 的 iterate()和 generate()创建一个无限的 Stream 对象。
java
@Test
public void test4()
{
//PrintStream ps = System.out;
//遍历10个偶数值,从0开始加2得到10个
Stream.iterate(0,t -> t + 2).limit(10).forEach(System.out::println);
//随机生成6个数值
Stream.generate(Math::random).limit(6).forEach(System.out::println);
}
1.3、中间操作
多个中间操作可以连接起来行一个 Stream 流水线,除非流水线上触发终止操作,否则中间操作不会执行任何处理,而在终止操作时一次性全部处理,这样处理方式称为"惰性求值"。
1.3.1、筛选与切片
java
@Test
public void test5()
{
List<Users> list = getUsers();
//创建Stream对象
Stream<Users> stream = list.stream();
//筛选人员信息年龄大于23的人员信息
stream.filter(users -> users.getUserage() > 23).forEach(System.out::println);
System.out.println("-------------");
//筛选人员信息年龄大于25的人员信息
//此处运行出错,因为上面筛选完年龄大于23的人员信息后,该stream就已经终止操作了,如果要再次使用
//则必须重新创建Stream对象
//stream.filter(users -> users.getUserage() > 25).forEach(System.out::println);
list.stream().filter(users -> users.getUserage() > 25).forEach(System.out::println);
}