Java8 新特性 -- Lambda 表达式的常规用法

1、Java8 新特性 – Lambda 表达式

1.1、单方法接口使用 Lambda 表达式

1
2
3
4
5
6
7
8
9
10
11
12
csharp复制代码public interface ITest {
/**
* go
*/
void go();
}

public static void main(String[] args) {
ITest t = ()->{
System.out.println(333);
};
}

使用场景:单接口快速创建实现类。

1.2、Lambda 中的方法引用运算符 ‘::’ 用法

1
2
3
csharp复制代码public void test(){}

public static void staticTest(){}

该运算符可用于以下场景:

(1)类::实例方法名

Person::test

(2)类::静态方法名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
java复制代码public class TestComponent {

@FunctionalInterface
public interface ITest {
int p(int i);
}

public static void runTest(ITest test,int i){
test.p(i);
}
public static int case1(int i) {
return i;
}

public static void main(String[] args) {
TestComponent.runTest(TestComponent::case1,7);
}
}

(3)对象::实例方法名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
java复制代码public class TestComponent {

@FunctionalInterface
public interface ITest {
int p(int i);
}

public static void runTest(ITest test,int i){
test.p(i);
}
public int case1(int i) {
return i;
}

public static void main(String[] args) {
TestComponent testComponent = new TestComponent();
TestComponent.runTest(testComponent::case1,7);
}
}

后两种可以这样理解:“::” 是方法引用操作符,传递的是方法的引用,在接口调用唯一方法的时候就是在调用传递进来的方法引用,所以在以上语法的基础上,只要保持返回值和参数完全一致就能将方法传递进去。

1.3、Lambda 中的 stream() 做了哪些优化?

优化 1:操作并行。
Lambda 在执行操作方法的时候会尽可能的多执行用户操作。比如我们需要将一个集合排序、筛选等操作,常规处理可能会将集合进行多次迭代处理数据,而 stream api 在执行的时候会将这些操作放到一个迭代中操作。

优化 2:节省存储空间。
在我们的常规方法中,一个排序后的操作可能会放置到新的集合中存储,而在 stream 中是在触发结束装后才会进行计算操作,省去了中间的存储操作。

具体可参考 :www.cnblogs.com/CarpenterLe…

1.4、stream api

对象准备:

1
2
3
4
5
6
7
8
less复制代码@Data
@Accessors(chain = true)
public class Person {

private Integer id;

private String name;
}

filter:过滤流,取匹配条件表达式的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
scss复制代码public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person().setName("都覅说").setId(1));
list.add(new Person().setName("认为我").setId(7));
list.add(new Person().setName("而为人发").setId(8));
list.add(new Person().setName("都发").setId(10));
list.add(new Person().setName("都发").setId(3));
list.add(new Person().setName("过的").setId(4));
// 保留 id > 6 的数据
list.stream().filter(p->p.getId() > 6).collect(Collectors.toList()).forEach(System.out::println);

}

输出:
Person(id=7, name=认为我)
Person(id=8, name=而为人发)
Person(id=10, name=都发)

map:转换流,将一种数据类型转换成另外一种数据类型,转换的类型取决于 Function 的 apply 返回的数据类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
scss复制代码    public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person().setName("都覅说").setId(1));
list.add(new Person().setName("认为我").setId(7));
list.add(new Person().setName("而为人发").setId(8));
list.add(new Person().setName("都发").setId(10));
list.add(new Person().setName("都发").setId(3));
list.add(new Person().setName("过的").setId(4));

List<Integer> collect = list.stream().map(p -> 1).collect(Collectors.toList());
System.out.println(collect);
List<String> collect1 = list.stream().map(Person::getName).collect(Collectors.toList());
System.out.println(collect1);
}

输出:
[1, 1, 1, 1, 1, 1]
[都覅说, 认为我, 而为人发, 都发, 都发, 过的]

mapToInt:转换流,将数据类型转换成 int 类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
scss复制代码public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person().setName("都覅说").setId(1));
list.add(new Person().setName("认为我").setId(7));
list.add(new Person().setName("而为人发").setId(8));
list.add(new Person().setName("都发").setId(10));
list.add(new Person().setName("都发").setId(3));
list.add(new Person().setName("过的").setId(4));

int[] ints = list.stream().mapToInt(Person::getId).toArray();
System.out.println(Arrays.toString(ints));

// 求平均值
double v = list.stream().mapToInt(Person::getId).average().orElse(0);
System.out.println(v);
}

输出:
[1, 7, 8, 10, 3, 4]
5.5

mapToLong:转换流,将数据转换成 long 类型

mapToDouble:转换流,将数据类型转化成 double 类型

distinct:去重,去重规则是根据 equals 和 hashCode 方法来过滤的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
less复制代码public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person().setName("都覅说").setId(1));
list.add(new Person().setName("认为我").setId(7));
list.add(new Person().setName("而为人发").setId(8));
list.add(new Person().setName("都发").setId(10));
list.add(new Person().setName("都发").setId(10));
list.add(new Person().setName("都发").setId(3));
list.add(new Person().setName("过的").setId(4));
list.add(new Person().setName("过的").setId(4));

List<Person> collect = list.stream().distinct().collect(Collectors.toList());
System.out.println(collect);

}

[Person(id=1, name=都覅说), Person(id=7, name=认为我), Person(id=8, name=而为人发), Person(id=10, name=都发), Person(id=3, name=都发), Person(id=4, name=过的)]

sorted:排序

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
less复制代码    public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person().setName("都覅说").setId(1));
list.add(new Person().setName("认为我").setId(7));
list.add(new Person().setName("而为人发").setId(8));
list.add(new Person().setName("都发").setId(10));
list.add(new Person().setName("都发").setId(10));
list.add(new Person().setName("都发").setId(3));
list.add(new Person().setName("过的").setId(4));
list.add(new Person().setName("过的").setId(4));

// 根据 ID 降序排列
List<Person> collect = list.stream().sorted(Comparator.comparing(Person::getId).reversed()).collect(Collectors.toList());
System.out.println(collect);

}


public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person().setName("而为人发").setId(8).setPerson(new Person().setId(21)));
list.add(new Person().setName("都发").setId(10).setPerson(new Person().setId(120)));

// 根据 person 里面的 person 的 ID 升序排列
List<Person> collect = list.stream().sorted(Comparator.comparing(Person::getPerson, Comparator.comparingInt(Person::getId))).collect(Collectors.toList());
System.out.println(collect);

}

public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person().setName("都覅说").setId(null));
list.add(new Person().setName("认为我").setId(7));
list.add(new Person().setName("都发").setId(null));
list.add(new Person().setName("都发").setId(3));
list.add(null);
list.add(new Person().setName("过的").setId(4));

// 根据 person 的 ID 升序排列,如果 person 对象是 null 或者 getId 是 null 则放置在前面排列
List<Person> collect = list
.stream()
.sorted(Comparator.nullsFirst(
Comparator.comparing(Person::getId,Comparator.nullsFirst(Integer::compareTo))
))
.collect(Collectors.toList());
System.out.println(collect);

}

输出:[null, Person(id=null, name=都覅说, person=null), Person(id=null, name=都发, person=null), Person(id=3, name=都发, person=null), Person(id=4, name=过的, person=null), Person(id=7, name=认为我, person=null)]



public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person().setName("都覅说").setId(32).setAge(3));
list.add(new Person().setName("认为我").setId(7).setAge(32));
list.add(new Person().setName("都发").setId(3).setAge(24));
list.add(new Person().setName("果然舒服").setId(3).setAge(33));
list.add(new Person().setName("过的").setId(4).setAge(323));

// 先按照 id 升序排列,如果 ID 相同再按照 age 升序排列
List<Person> collect = list
.stream()
.sorted(Comparator.comparing(Person::getId).thenComparing(Person::getAge))
.collect(Collectors.toList());
System.out.println(collect);

}

peek:中间流操作,和 map 功能有点像,只不过没有替换操作,作用是用来调试中间状态的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
csharp复制代码 List<String> arr = new ArrayList<>();
arr.add("fgdf");
arr.add("45rtfsd");
arr.add("534werf");
arr.add("fsdefg");
arr.add("terttre");

List<String> collect = arr.stream().peek(p -> p = "2").collect(Collectors.toList());
System.out.println(collect);

输出:[fgdf, 45rtfsd, 534werf, fsdefg, terttre]


List<String> arr = new ArrayList<>();
arr.add("fgdf");
arr.add("45rtfsd");
arr.add("534werf");
arr.add("fsdefg");
arr.add("terttre");

// 一定要有终止操作,不然不会有输出
arr.stream()
.peek(System.out::println)
.collect(Collectors.toList());

limit:保留前 n 条数据。

skip:跳过 n 条数据

forEach:遍历,可能不是按照集合的顺序遍历

forEachOrdered:按照顺序遍历

reduce:数据计算

1
2
3
4
5
6
7
8
9
10
11
less复制代码public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person().setName("都覅说").setId(32).setAge(3));
list.add(new Person().setName("认为我").setId(7).setAge(32));
list.add(new Person().setName("都发").setId(3).setAge(24));
list.add(new Person().setName("果然舒服").setId(3).setAge(33));
list.add(new Person().setName("过的").setId(4).setAge(323));

Integer num = list.stream().map(Person::getAge).reduce(Integer::sum).orElse(0);

}

collect:将流转换成对象类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
scss复制代码public static void main(String[] args) {
// 最常用的用法
List<Person> s = new ArrayList<>();
s.add(new Person().setId(1).setName("jfgkj"));
List<String> collect = s.stream().map(Person::getName).collect(Collectors.toList());
}

分组
public static void main(String[] args) {
List<Person> s = new ArrayList<>();
s.add(new Person().setId(1).setName("jfgkj"));
s.add(new Person().setId(2).setName("fdkgjhd"));
s.add(new Person().setId(3).setName("fdkgjhd"));
// groupingBy 里面填的就是 key 值,每操作一条数据,只要他们符合 key 的规则,就会放在一个集合里面,
// 比如下面,key 是 name,将 name 放在一个 map 里面,如果下一个 name 存在于 map 中的 name 中,就放置在 List 里面。
// 这里面的规则可以自己随便定义
Map<String, List<Person>> collect = s.stream().collect(Collectors.groupingBy(Person::getName));
System.out.println(collect);

}

输出 {fdkgjhd=[TestComponent.Person(id=2, name=fdkgjhd), TestComponent.Person(id=3, name=fdkgjhd)], jfgkj=[TestComponent.Person(id=1, name=jfgkj)]}

min:最小值

max:最大值

count:统计数量

anyMatch:是否有匹配条件语句的数据

allMatch:数据是否全部匹配条件语句

noneMatch:数据是否全部不匹配

1.5、Predicate 与 Function

除了这些,JDK 中还预定义了很多 FunctionalInterface 类,这样我们就无需自己去重复定义一些类似的接口了。

Function

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
typescript复制代码@FunctionalInterface
public interface Function<T, R> {

/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);

default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}


default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}


static <T> Function<T, T> identity() {
return t -> t;
}
}

Function 可以接受任意的 Lambda 表达式,当然参数只能是一个的。

1
ini复制代码Function<Person, String> getName = Person::getName;

Function<T, R> 中 T 决定 参数类型,R 决定返回值类型。

Predicate

Predicate 相当于在 Function 的基础上限定了返回值的类型,常用于接收条件表达式。

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
scss复制代码@FunctionalInterface
public interface Predicate<T> {

boolean test(T t);


default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}


default Predicate<T> negate() {
return (t) -> !test(t);
}


default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}


static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
1
ini复制代码Predicate<Integer> s = t -> t > 1;

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%