一、Lambda表达式
1.1 Lambda表达式简介
Lambda表达式是一个为了JDK1.8以后的一种新的语法,比匿名内部类更加的便捷。
匿名内部类在实现的时候还需要重写方法,但是Lambda表达式不需要对方法进行重写。
(匿名内部类中被重写方法的形式参数列表) -> {方法体}
-> 是语法形式,没有实际的意义
优点:Lambda表达式关注的是接口中的【参数】和【返回值】
一般是为了用于方法的增强,直接作为方法的参数,实现【函数式编程】
1.2 函数式接口
- @FunctionalInterface注解修饰的接口都是函数式接口
- 函数式接口里面的方法必须有且只有一个【缺省属性】为public abstract修饰的方法
- lambda表达式与匿名内部类进行实现代码功能执行的方法都是函数式接口中的方法
1.3 代码案例介绍Lambda表达式和匿名内部类区别
无参构造无返回值构造方法(某啥用,只能当了解Lambda表达式的开始)
匿名内部类
函数式接口定义
//定义一个名为Test的函数式接口
@FunctionalInterface
interface Test{
void test();
}
匿名内部类代码演示
@FunctionalInterface
interface Test{
void test();
}
public class Demo4 {
public static void main(String[] args) {
new Test(){
@Override
public void test() {
System.out.println("匿名内部类实现函数式接口方法");
}
}.test();
}
}
Lambda表达式代码演示
Test test = () -> {
System.out.println("123");
};
test.test();`
这样我们可以看出Lambda表达式和匿名内部类在代码的书写上比较非常的简洁!
代码分析
() :里面是形式参数列表,里面放入的是接口中方法对应的形式引用参数 -> :Lambda表达式的一种书写方法,无特殊意义。 {} :里面写方法,本例子没有写入参数,而是直接输出了一条输出语句
也可以在main函数中写一个方法
/**
* @param t 函数式接口 Test
*/
public static void testLambda(Test t) {
t.test();
}
在main中
testLambda(() -> System.out.println("无参无返回值没啥意义"));
方法引用方法,另外写一个方法
public static void test(){
System.out.println("方法引用");
}
然后在main中方法引用
testLambda(Demo4::test);
//Demo4是类名,test是方法引用的方法名
1.4 实战开发的作用
前面学习过一个比较器接口,Comparator,这个接口就是一个函数式接口。
1.4.1 TreeSet中直接调用Comparator接口排序
在TreeSet中可以直接使用,因为TreeSet接口的构造方法中参数为Comparator<? super E> comparator
,代码如下:
TreeSet<Person> list = new TreeSet<>((o1,o2)->{return o1.getAge() - o2.getAge();});
list.add(new Person(1,"张三",13,true));
list.add(new Person(2,"张四",63,true));
list.add(new Person(3,"张五",23,false));
list.add(new Person(5,"张六",53,true));
System.out.println(list);
输出的结果为:
[Person{id=1, name='张三', age=13, gender=true}, Person{id=3, name='张五', age=23, gender=false}, Person{id=5, name='张六', age=53, gender=true}, Person{id=2, name='张四', age=63, gender=true}]
1.4.2 Comparator
//函数式接口,比较器
@FunctionalInterface
interface Comparator<T> {
int compare(T o1, T o2);
}
public class Demo4 {
public static void main(String[] args) {
Person[] array = new Person[5。
//随机生成几个年龄不同的Person对象
for (int i = 0; i < array.length; i++) {
int age = (int) (Math.random() * 50);
array[i] = new Person(i + 1, "张三", age, false);
}
testLambda(array, (o1, o2) -> o1.getId() - o2.getId());
for (Person person : array) {
System.out.println(person);
}
}
public static void testLambda(Person[] array, Comparator<Person> condition) {
for (int i = 0; i < array.length - 1; i++) {
int index = i;
for (int j = i + 1; j < array.length; j++) {
if (condition.compare(array[index], array[j]) > 0) {
index = j;
}
}
if (index != i) {
Person temp = array[index];
array[index] = array[i];
array[i] = temp;
}
}
}
}
1.4.3 Predicate 过滤器接口
@FunctionalInterface
interface Predicate<T> {
boolean test(T t);
}
public class Demo5 {
public static void main(String[] args) {
Person[] array = new Person[5];
//随机生成五个年龄不同的Person对象
for (int i = 0; i < array.length; i++) {
int age = (int) (Math.random() * 50);
array[i] = new Person(i + 1, "张三", age, false);
}
//过滤年龄小于10的Person
Person[] temp = testLambda(array, p -> p.getAge() > 10);
for (Person person : temp) {
System.out.println(person);
}
}
public static Person[] testLambda(Person[] array, Predicate<Person> filter) {
Person[] temp = new Person[array.length];
int count = 0;
for (int i = 0; i < array.length; i++) {
if (filter.test(array[i])) {
temp[count++] = array[i];
}
}
return temp;
}
}
1.4.4 Function<T,R>
@FunctionalInterface
interface Function<T, R> {
R apply(T t);
}
public class Demo6 {
public static void main(String[] args) {
String str = "开封有个包青天";
//Lambda表达式
int i = testLambda(str, s -> s.length());
System.out.println(i);
// 方法引用
int ret = testLambda("邠州有个范仲淹", Demo6::test);
System.out.println(ret);
}
public static int testLambda(String str, Function<String, Integer> fun) {
return fun.apply(str);
}
public static int test(String str) {
return str.length();
}
}
二、Stream流
Stream流的操作是非常的简单的,只需要知道Stream流中对应的方法,直接调用就可以。JDK1.8版本以上支持
想要调用里面的方法第一步就是转换成Stream流对象
//Stream流支持的是数组或者集合
Stream<T> stream();//集合对象转换为Stream流
Stream<T> Arrays.Stream(T[] t);//数组转换为Stream流
Stream里面的方法
//跳过前面的几个元素,不要头几个
Stream<T> skip(long n);
//保留几个元素,后面的全部不要
Stream<T> limit(long n);
//对当前Stream流中的元素进行排序,里面的数据是自然顺序
Stream<T> sorted();
//对当前的Stream流中的元素进行排序,里面的数据是由Comparator函数式接口规范
Stream<T> sorted(Comparator<? super T> comparator);
//判断过滤当前Stream流里可以保留的数据,满足保留,不满足移除
Stream<T> filter(Predicate<? super T> pre)
//当前Stream流中对应的所有元素去重操作
Stream<T> distinck();
//当前Stream流存储的数据情况转换为 Function 函数式接口要求的返回值类型,完成类型转换
Stream<R> map(Function<T,R> fun);
Stream流中的终止方法
//返回Stream流对应的数据元素个数
long count();
//针对于当前Stream流的处理方法
void forEach(Comsumer<? super T> con);
//Stream流转换方法,转换为用户需求的集合对象
<R,A> R collect(Collection<> super T,A,R> collector);
常用:
Collectors.toList() 目标存储集合类型为List集合
Collectors.toSet() 目标存储集合类型为Set集合
//Stream流存储的元素内容转换为Object数组返回
Object toArray();
这就是Stream中常用的方法,接下来需要对方法进行讲解使用:
我们先定义一个ArrayList集合,然后里面的泛型定义为Person类
public class Demo3 {
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<>();
//在循环中创建 20 个Person对象,并且里面的年龄是随机生成的,名字后面带有标号
for (int i = 0; i < 20; i++) {
list.add(new Person("张三" + (i+1), (int)(Math.random()*40)));
}
//集合转为Stream流,并且眼红forEach方法输出!
list.stream()
.forEach(System.out::println);
}
}
最后运行结果为:
public class Demo3 {
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<>();
//在循环中创建 20 个Person对象,并且里面的年龄是随机生成的,名字后面带有标号
for (int i = 0; i < 20; i++) {
list.add(new Person("张三" + (i+1), (int)(Math.random()*40)));
}
//集合转为Stream流,并且眼红forEach方法输出!
list.stream()
//去除前面5个
.skip(5)
//只要10个
.limit(10)
.forEach(System.out::println);
}
}
从上面的代码中可以看出,去除前面的5个说明张三1-5没了,limit里面的参数为10,说明只要10个,结果为张三6到张三15
![[]](https://img-blog.csdnimg.cn/ee69aed598844896b13ad09bab87034a.png)
我们在里面添加一个sorted()方法,让最后输出的结果按照年龄的大小进行依次排序。
list.stream()
//去除前面5个
.skip(5)
//只要10个
.limit(10)
//排序
.sorted((p1,p2)-> p1.getAge() - p2.getAge())
.forEach(System.out::println);
截图中可以发现我们的结果是按照年龄的顺序排序的~~
但是可以发现这里是用Lambda方法来写的,但是这个Lambda表达式是暗灰色的,说明IDE提醒我们,这个Lambda表达式太Low了对我们进行了一波鄙视=_=,我们可以先看一下IDE希望我们写的代码(Alt+回车 再回车):
sorted(Comparator.comparingInt(Person::getAge))
这个是IDE希望我们在sorted()当中写的比较方法,好家伙,刚学完Lambda就用不了,其实不是这样滴,这是一个非常特殊的书写方法,目前也只是在比较ArrayList集合中发现了这样写IDE会鄙视~
后期会对方法引用进行深入的讲解,会详细的讲一下这个方法,里面的源码用到了好几个函数式接口,并且用到了反射的原理~
其他的方法可以依次进行测试:
list.stream()
.filter(person -> person.getAge() > 30)
.forEach(System.out::println);
上面的filter方法过滤的是30岁以下的Person对象
其他方法可以自己尝试演示~~