0%

Lambda表达式

Lambda表达式的概述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
什么是Lambda表达式?
Lambda表达式是JDK1.8开始之后的新技术,是一种代码的新语法。
是一种特殊写法,
作用:“核心目的是为了简化匿名内部类的代码写法”。

Lambda表达式的格式:
(匿名内部类被重写方法的形参列表) -> {
被重写方法的方法体代码。
}

-> 就是一个新语法,没有实际含义,但是不能省略!

Lambda表达式的使用前提:
(1)Lambda表达式并不能简化所有匿名内部类的写法。
(2)Lambda表达式只能简化接口中只有一个抽象方法的匿名内部类形式。

Lambda表达式只能简化函数式接口的匿名内部类写法:
a.首先必须是接口。
b.接口中只能有一个抽象方法。
小结:
Lambda表达式只能简化接口中只有一个抽象方法的匿名内部类写法。
接口中只有一个抽象方法的接口称为函数式接口。
Lambda只能简化函数式接口的匿名内部类写法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Lambda表达式简化Runnable接口的匿名内部类写法

@FunctionalInterface函数式接口注解:
一旦某个接口加上了这个注解,这个接口只能有且仅有一个抽象方法。
这个接口就可以被Lambda表达式简化。

public class LambdaDemo {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":执行~~~");
}
});
t.start();

Thread t1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName()+":执行~~~");
});
t1.start();

new Thread(() -> {
System.out.println(Thread.currentThread().getName()+":执行~~~");
}).start();

new Thread(() -> System.out.println(Thread.currentThread().getName()+":执行~~~")).start();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Lambda简化Comparator接口匿名内部类写法

public class CollectionsDemo02 {
public static void main(String[] args) {
List<Student> lists = new ArrayList<>();
Student s1 = new Student("李铭",18,'男');
Student s2 = new Student("冯龙",23,'男');
Student s3 = new Student("王乐乐",21,'男');
Collections.addAll(lists , s1 , s2 , s3);

// 按照年龄进行升序排序!
Collections.sort(lists, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
return s1.getAge() - s2.getAge();
}
});

// 简化写法
Collections.sort(lists ,(Student t1, Student t2) -> {
return t1.getAge() - t2.getAge();
});

Collections.sort(lists ,(Student t1, Student t2) -> t1.getAge() - t2.getAge());

// 参数类型可以省略
Collections.sort(lists ,( t1, t2) -> t1.getAge() - t2.getAge());

System.out.println(lists);


}
}

Lambda表达式的省略写法

1
2
3
4
5
1)如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写,同时要省略分号!
(2)如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写。
此时,如果这行代码是return语句,必须省略return不写,同时也必须省略";"不写
(3)参数类型可以省略不写。
(4)如果只有一个参数,参数类型可以省略,同时()也可以省略。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class LambdaDemo01 {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("胡伟光");
names.add("甘挺");
names.add("洪磊");

names.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});

names.forEach((String s) -> {
System.out.println(s);
});

names.forEach((s) -> {
System.out.println(s);
});

names.forEach(s -> {
System.out.println(s);
});

names.forEach(s -> System.out.println(s) );

names.forEach(System.out::println);


}
}

方法引用的概述。(了解)

1
2
3
4
5
6
7
8
方法引用:
方法引用是为了进一步简化Lambda表达式的写法。
方法引用的格式:类型或者对象::引用的方法。
关键语法是:“::”

小结:
方法引用可以进一步简化Lambda表达式的写法。
关键语法是:“::”

方法引用有四种形式

1
2
3
4
1.静态方法的引用。
2.实例方法的引用。
3.特定类型方法的引用。
4.构造器引用。

静态方法的引用

1
2
3
4
5
6
7
8
9
10
1.静态方法的引用。
引用格式:
类名::静态方法。
简化步骤:
a.定义一个静态方法,把需要简化的代码放到一个静态方法中去。
静态方法引用的注意事项
” 重要:被引用的方法的参数列表要和函数式接口中的抽象方法的参数列表一致。“
小结:
静态方法引用的格式: 类名::静态方法。
重要:被引用的方法的参数列表要和函数式接口中的抽象方法的参数列表一致,才可以引用简化!

实例方法的引用

1
2
3
4
5
6
2.实例方法的引用
格式: 对象::实例方法。
简化步骤:
a.定义一个实例方法,把需要的代码放到实例方法中去。
实例方法引用的注意事项
” 重要:被引用的方法的参数列表要和函数式接口中的抽象方法的参数列表一致。“

特定类型方法的引用

1
2
3
4
5
6
3.特定类型方法的引用。
特定类型:String ,任何类型。
格式:特定类型::方法。
注意:
如果第一个参数列表中的形参中的第一个参数作为了后面的方法的调用者,
并且其余参数作为后面方法的形参,那么就可以用特定类型方法引用了。

构造器引用

1
2
3
4
5
6
7
4.构造器引用。
格式是:类名::new。
注意点:前后参数一致的情况下,又在创建对象就可以使用构造器引用
s -> new Student(s) => Student::new

小结:
方法引用是可遇不可求,能用则用,不能用就不要用!

Stream流的强大

1
2
3
4
5
6
7
8
9
10
11
什么是Stream流?
在Java 8中,得益于Lambda所带来的函数式编程,
引入了一个全新的Stream流概念 ,用于解决已有集合/数组类库有的弊端。

Stream流能解决什么问题?
可以解决已有集合类库或者数组API的弊端。
Stream认为集合和数组操作的API很不好用,所以采用了Stream流简化集合和数组的操作!!

小结:
Stream流是用来简化集合类库或者数组API的弊端。
Stream流其实就一根传送带,元素在上面可以被Stream流操作。

Stream流的获取

1
2
3
4
5
6
7
8
9
10
11
Stream流式思想的核心:
是先得到集合或者数组的Stream流(就是一根传送带)
然后就用这个Stream流操作集合或者数组的元素。
然后用Stream流简化替代集合操作的API.

集合获取流的API:
(1) default Stream<E> stream();

小结:
集合获取Stream流用: stream();
数组:Arrays.stream(数组) / Stream.of(数组);

Stream流的常用API

1
2
3
4
5
6
7
8
9
forEach : 逐一处理(遍历)
count:统计个数
-- long count();
filter : 过滤元素
-- Stream<T> filter(Predicate<? super T> predicate)
limit : 取前几个元素
skip : 跳过前几个
map : 加工方法
concat : 合并流。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class StreamDemo01 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.add("张三丰");

list.stream().filter( s -> s.length() == 3 ).filter( s -> s.startsWith("张"))
.forEach( System.out::println);
// 统计数量
long count = list.stream().filter( s -> s.length() == 3 )
.filter( s -> s.startsWith("张")).count();
System.out.println(count);
// 取前2个
list.stream().filter(s -> s.length() == 3).limit(2)
.forEach( System.out::println);
// 跳过前2个
list.stream().filter(s -> s.length() == 3).skip(2)
.forEach( s-> System.out.println(s));

// 需求:把名称都加上“黑马的:+xxx”
list.stream().map(a -> "黑马的:"+a).forEach(System.out::println);

// 需求:把名称都加工厂学生对象放上去!!
// list.stream().map(name -> new Student(name)).forEach(System.out::println);

list.stream().map(Student::new).forEach(System.out::println);

// 数组流
Stream<Integer> s1 = Stream.of(10, 20 ,30 ,40);
// 集合流
Stream<String> s2 = list.stream();
// 合并流
Stream<Object> s3 = Stream.concat(s1,s2);
s3.forEach(System.out::println);

}
}

终结与非终结方法

1
2
3
4
5
6
终结方法:一旦Stream调用了终结方法,流的操作就全部终结了,不能继续使用,
只能创建新的Stream操作。
终结方法: foreach , count。

非终结方法:每次调用完成以后返回一个新的流对象,
可以继续使用,支持链式编程!

收集Stream流:把Stream流的数据转回成集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
引入:
Stream的作用是:把集合转换成一根传送带,借用Stream流的强大功能进行的操作。
但是实际开发中数据最终的形式还是应该是集合,最终Stream流操作完毕以后还是要转换成集合。
这就是收集Stream流。

收集Stream流的含义:就是把Stream流的数据转回到集合中去。

Stream流:手段。
集合:才是目的。

小结:
收集Stream流的含义:就是把Stream流的数据转回到集合中去。

熟练函数式编程,如Lambda表达式简化函数式接口的匿名内部类形式,
以及四种方法引用简化Lambda表达式,以及流式编程思想如Stream简化集合或者数组的操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class StreamDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.add("张三丰");

Stream<String> zhangLists = list.stream().filter(s -> s.startsWith("张"));
// 把stream流转换成Set集合。
Set<String> sets = zhangLists.collect(Collectors.toSet());
System.out.println(sets);

// 把stream流转换成List集合。
Stream<String> zhangLists1 = list.stream().filter(s -> s.startsWith("张"));
List<String> lists= zhangLists1.collect(Collectors.toList());
System.out.println(lists);

// 把stream流转换成数组。
Stream<String> zhangLists2 = list.stream().filter(s -> s.startsWith("张"));
Object[] arrs = zhangLists2.toArray();
// 可以借用构造器引用申明转换成的数组类型!!!
String[] arrs1 = zhangLists2.toArray(String[]::new);
}
}