1.lambda表达式
lambda表达式是为了简化编程而生。在java中,一些很常见的操作总是包含一些“静态”代码,这里的静态值得是:无论我们在该操作中实现什么逻辑,这些代码必须得有而且形式也一样。比如使用匿名内部类的java线程,按钮的点击事件等。
lambda表达式就是要替代只有一个抽象方法的匿名内部类,让代码变得更简洁。
因为这些“静态”代码形式是固定的,所以编译器能够自动推断出来,或者可以理解为,那些被lambda表达式替换掉的“静态”代码编译器在编译时会自动补上(纯属个人理解)。
@FunctionalInterface 注解用于只有一个抽象方法的接口,而lambda表达式就是作用在这种表达式上的。
下面的代码根据抽象方法的类型分成四种进行讨论,分别是:无参无返回值,有参无返回值,无参有返回值,有参有返回值
定义 FunctionalInterface类型的接口:
/**
* FunctionalInterface注解只用于只有一个抽象方法的接口,有且只有这种接口可以用于lambda表达式
*/
/**
* 抽象方法无参无返回值
*/
@FunctionalInterface
interface TestInterface1{
void mmethod1();
}
/**
* 抽象方法有参无返回值
*/
@FunctionalInterface
interface TestInterface2{
void method2(String str1,String str2);
}
/**
* 抽象方法无参有返回值
*/
@FunctionalInterface
interface TestInterface3{
String method3();
}
/**
* 抽象方法有参有返回值
*/
@FunctionalInterface
interface TestInterface4{
boolean method4(String str1,String str2);
}
lambda表达式和等效的匿名内部类:
/**
* Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。
*/
public class TestClass {
void testMethod1(TestInterface1 interface1){
interface1.mmethod1();
}
void testMethod2(TestInterface2 interface2){
interface2.method2("Hello","World");
}
void testMethod3(TestInterface3 interface3){
String s=interface3.method3();
System.out.println(s);
}
void testMethod4(TestInterface4 interface4){
boolean b=interface4.method4("Hello","World");
System.out.println(b);
}
/**
* ***************************************************
* 测试方法
* ***************************************************
*/
public void test(){
/**
* 无参无返回值
*/
testMethod1(new TestInterface1() {
@Override
public void mmethod1() {
System.out.println("匿名内部类无参无返回值");
}
});
testMethod1(()->System.out.println("lambda无参无返回值"));
/**
* 有参无返回值
*/
testMethod2(new TestInterface2() {
@Override
public void method2(String str1, String str2) {
System.out.println("匿名内部类"+str1+str2);
}
});
testMethod2((str1,str2)->{System.out.println("lambda有参无返回值"+str1+str2);});
/**
* 无参有返回值
*/
testMethod3(new TestInterface3() {
@Override
public String method3() {
String str1="Hello",str2="World";
System.out.println("匿名内部类无参有返回值");
return str1+str2;
}
});
//两种写法
testMethod3(()-> "Hello World");
testMethod3(()->{
String str1="Hello",str2="World";
System.out.println("lambda无参有返回值");
return str1+str2;
});
/**
* 有参有返回值
*/
testMethod4(new TestInterface4() {
@Override
public boolean method4(String str1, String str2) {
System.out.println("匿名内部类有参有返回值");
return str1.equals(str2);
}
});
testMethod4((str1,str2)->{
System.out.println("lambda表达式有参有返回值");
return str1.equals(str2);
});
/**
* java线程的lambda表达式写法
*/
new Thread(()->{
try{
Thread.sleep(1000);
System.out.println("java线程");
}
catch (Exception e){}
}).start();
}
}
参考博客:https://www.cnblogs.com/yulinfeng/p/8452379.html 感谢作者
2.Stream流
java8的stream流是为了更简洁的迭代处理集合。
下面的代码是stream常见的操作:
1.首先是两个构建两个用于测试的集合:
public List<Teacher> getTeachers(){
List<Teacher> teachers=new LinkedList<>();
teachers.add(new Teacher(19,"zhangSan","女"));
teachers.add(new Teacher(45,"liSi","男"));
teachers.add(new Teacher(20,"wangWU","女"));
teachers.add(new Teacher(19,"找Liu","男"));
return teachers;
}
public List<Student> getStudents(){
List<Student> students=new LinkedList<>();
students.add(new Student(12,"xiaoMing"));
students.add(new Student(10,"xiaoHong"));
students.add(new Student(6,"xiaoHua"));
return students;
}
Teacher的构造参数依次为age,name,sex。Student的构造参数依次为age,name。
2.对集合最常见的一些操作:
/**
* 像filter,map 这样只描述 Stream,最终不产生新集合的方法叫作惰性求值方法;而像 count,collect 这样
* 最终会从 Stream 产生值的方法叫作及早求值方法
*/
/**
* 判断一个操作是惰性求值还是及早求值很简单:只需看它的返回值。如果返回值是 Stream,
* 那么是惰性求值;如果返回值是另一个值或为空,那么就是及早求值
*/
/**
* 方法引用是一种引用方法的轻量级语法,形如:ClassName::methodName。
*/
public void test(){
/**
* 统计年龄大于10的人数,filter是对stream对象里面的值进行过滤,该函数必须返回true或者false
*/
long count=getTeachers().stream().filter(teacher -> teacher.getAge()>10).count();
//lambda表达式后面也可以是一个代码块,类似于filter这种操作,需要在代码块中返回一个布尔值
long count2=getTeachers().stream().filter(teacher -> {
teacher.setAge(teacher.getAge()-5);
return teacher.getAge()>10;}).count();
//得到性别为女的集合并使用forEach做遍历输出
List<Teacher> list=getTeachers().stream().filter(teacher -> teacher.getSex().equals("女"))
.collect(Collectors.toList());
//forEach,用于遍历集合,下面两行代码是等效的
list.stream().forEach(teacher -> System.out.println(teacher));
list.forEach(System.out::println);//传递的是方法的引用,编译环境能够知道需要将什么值作为参数传入到该方法中
/**
* map可以将一种类型转化为另一种类型,将一个流中的值转换成一个新的流,下面的代码是将Teacher转换成了Integer
* map返回的是什么类型,就转换成了什么类型
*/
List<Integer> list1=getTeachers().stream().map(teacher -> teacher.getAge()+12).collect(Collectors.toList());//返回年龄集合,每个年龄加了12岁
List<Integer> list3=Stream.of("Hello","World","java","I").map(s -> s.length()).collect(Collectors.toList());//将字符串的长度组合成一个数组
//使用Stream.of(...)的方式构建一个stream
List<String> strings= Stream.of("a","b","c").collect(Collectors.toList());
//转换为set集合
Set<Integer> integers= Stream.of(23,34,11,66,12).collect(Collectors.toSet());
/**
* flatMap 方法可用 Stream 替换值,然后将多个 Stream 连接成一个 Stream
* flatMap将多个类型的集合,合并成一个集合,但是必须返回Stream类型。
* Teacher和Student都是Object子类,所以合并后用Object接收
*/
/**
* 控制台输出
* Teacher{age=19, name='zhangSan', sex='女', students=null}
* Teacher{age=45, name='liSi', sex='男', students=null}
* Teacher{age=20, name='wangWU', sex='女', students=null}
* Teacher{age=19, name='找Liu', sex='男', students=null}
* Student{age=12, name='xiaoMing'}
* Student{age=10, name='xiaoHong'}
* Student{age=6, name='xiaoHua'}
*/
List<Object> list4=Stream.of(getTeachers(),getStudents()).flatMap(objects -> objects.stream()).collect(Collectors.toList());
System.out.println(list4);
/**
* 获取集合中的最大值和最小值
* 使用get获取操作后的对象或者值
*/
Student stuAgeMin=getStudents().stream().min(Comparator.comparing(student -> student.getAge())).get();//获取年龄最小的学生
Student stuAgeMax=getStudents().stream().max(Comparator.comparing(student -> student.getAge())).get();//获取年龄最大的学生
/**
* 排序
*/
List<Teacher> teacherList=getTeachers().stream().sorted(Comparator.comparing(teacher -> teacher.getAge())).collect(Collectors.toList());
System.out.println(teacherList);//按老师年龄输出,年龄由小到大
List<Integer> numbers=Stream.of(9,12,5,2,11).sorted().collect(Collectors.toList());
numbers.forEach(System.err::print);//输出:2 5 9 11 12
System.out.println(stuAgeMin);
}
3.收集器collect更多的用法:
public void collectionTest(){
/**
* 生成一个字符串,该集合最后生成一个具有一定形式的字符串
* 希望将一个集合转换成这种形式的字符串: {item1.item2,item3...}
*/
//joining(...),第一个参数表示分隔符,第二个参数表示前缀,第三个参数表示后缀
String str=Stream.of(12,33,43,67,77,88,93).map(s->s.toString()).collect(Collectors.joining(",","{","}"));
System.err.println(str);//输出:{12,33,43,67,77,88,93}
/**
* 转换成其他的集合类
*
* 之前的操作都是将集合转换为List,Set这些抽象接口,Stream类在背后自动为我们选择合适的类型,
* 我们可以自定义转换的集合类型
*/
List<Integer> numbers2=Stream.of(9,12,5,2,11).sorted().collect(Collectors.toCollection(LinkedList::new));
List<String> numbers3=Stream.of(9,12,5,2,11).map(a -> a+"").collect(Collectors.toCollection(Vector::new));
//转换为Map对象,key和value分别是老师的名字和性别
Map<String,String> stringMap=getTeachers().stream().collect(Collectors.toMap(teacher->teacher.getName(),teacher -> teacher.getSex()));
for (Map.Entry<String,String> stringListEntry : stringMap.entrySet()) {
System.err.println(stringListEntry.getKey()+":"+stringListEntry.getValue());
}
/**
* 转换成值
*/
Optional<Teacher>t=getTeachers().stream().collect(Collectors.maxBy(Comparator.comparing(teacher -> teacher.getAge())));
Optional<Teacher>t2=getTeachers().stream().collect(Collectors.minBy(Comparator.comparing(teacher -> teacher.getAge())));
//计算平均年龄(平均数有可能是小数,所以要用都double来接收)
double averagingAge= getTeachers().stream().collect(Collectors.averagingInt(teacher->teacher.getAge()));
System.out.println(averagingAge);
/**
* 数据分块
*
* 该流操作是将一个集合其分解成两个集合,比如一个Teacher集合,想根据性别分成两个集合,这时就可以使用数据分块了
*
* 它使用 Predicate 对象判断一个元素应该属于哪个部分,并根据布尔值返回一
* 个 Map 到列表。因此,对于 true List 中的元素,Predicate 返回 true;对其他 List 中的
* 元素,Predicate 返回 false。
*/
Map<Boolean,List<Teacher>> maps=getTeachers().stream().collect(Collectors.partitioningBy(teacher -> teacher.getSex().equals("女")));
List<Teacher> t1=maps.get(true); t1.stream().forEach(teacher -> System.out.println(teacher));//输出所有女老师
maps.get(false).stream().forEach(teacher -> System.out.println(teacher));//输出所有男老师
/**
* 数据分组
*
* 数据分组是一种更自然的分割数据操作,与将数据分成 ture 和 false 两部分不同,可以使
* 用任意值对数据分组,返回的Map对象key是分组的字段
* 和sql中的group by很像
*/
Map<String,List<Teacher>>teacherListMap=getTeachers().stream().collect(Collectors.groupingBy(teacher -> teacher.getSex()));
List<Teacher> t3=teacherListMap.get("女"); t3.stream().forEach(teacher -> System.out.println(teacher));//输出所有女老师
teacherListMap.get("男").stream().forEach(teacher -> System.out.println(teacher)); //输出所有男老师
/**
* 组合收集器
*/
//根据老师性别分组并且输出个数(非常类似sql中的group by和聚合函数的使用),使用了counting()
Map<String,Long> counts=getTeachers().stream().collect(Collectors.groupingBy(teacher -> teacher.getSex(),Collectors.counting()));
System.err.println("女老师个数为"+counts.get("女"));//输出:女老师个数为2
System.err.println("男老师个数为"+counts.get("男"));//输出:男老师个数为4
//按照老师的性别输出老师的姓名,使用了mapping(...)方法,第一参数表示分组之后需要输出什么值,这里是输出name,第二个是以
//什么集合形式输出,这里是以List集合的方式输出
Map<String,List<String>> stringListMap=getTeachers().stream().collect(Collectors.groupingBy(teacher -> teacher.getSex(),Collectors.
mapping(teacher -> teacher.getName(),Collectors.toList())));
stringListMap.get("男").stream().forEach(System.err::println);//输出所有男老师的姓名
stringListMap.get("女").stream().forEach(System.err::println);//输出所有女老师的姓名
}
4.常见的终止操作
allMatch——检查是否匹配所有元素
anyMatch——检查是否至少匹配一个元素
noneMatch——检查是否没有匹配的元素
findFirst——返回第一个元素
findAny——返回当前流中的任意元素
count——返回流中元素的总个数
max——返回流中最大值
min——返回流中最小值