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

2023-11-20 14:44:12 浏览数 (1)

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腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞