1、Java8 新特性 -- Lambda 表达式
1.1、单方法接口使用 Lambda 表达式
代码语言:c#复制public interface ITest {
/**
* go
*/
void go();
}
public static void main(String[] args) {
ITest t = ()->{
System.out.println(333);
};
}
使用场景:单接口快速创建实现类。
1.2、Lambda 中的方法引用运算符 '::' 用法
代码语言:c#复制public void test(){}
public static void staticTest(){}
该运算符可用于以下场景:
(1)类::实例方法名
Person::test
(2)类::静态方法名
代码语言: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)对象::实例方法名
代码语言: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
对象准备:
代码语言:less复制@Data
@Accessors(chain = true)
public class Person {
private Integer id;
private String name;
}
filter:过滤流,取匹配条件表达式的数据。
代码语言: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 返回的数据类型。
代码语言: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 类型
代码语言: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 方法来过滤的。
代码语言: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:排序
代码语言: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 功能有点像,只不过没有替换操作,作用是用来调试中间状态的值。
代码语言:c#复制 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:数据计算
代码语言: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:将流转换成对象类型
代码语言: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
代码语言: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 表达式,当然参数只能是一个的。
代码语言:text复制Function<Person, String> getName = Person::getName;
Function<T, R>
中 T 决定 参数类型,R 决定返回值类型。
Predicate
Predicate 相当于在 Function 的基础上限定了返回值的类型,常用于接收条件表达式。
代码语言: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);
}
}
代码语言:text复制Predicate<Integer> s = t -> t > 1;
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!