Lambda表达式和Stream流执行流程

两个参数Lambda 表达式

两个参数的 Lambda 表达式使用,当函数体/方法体中只有一个return语句时,return和大括号都可以省略。

package com.wlx.day17;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TreeMap;

public class LambdaTest
{
    /**
     * 练习:
     * 	使用Lambda表达式的方式,分别对List集合进行倒序排序。
     */
    @Test
    public void  listDemo()
    {
        List<Integer>  list = new ArrayList<>();
        list.add(23);
        list.add(2);
        list.add(13);
        list.add(3);
        list.add(26);
//        list.sort((o1, o2) -> {return o1 > o2 ? -1:1;});
        //当函数体/方法体中只有一个return语句时,return和大括号都可以省略
        list.sort((o1, o2) -> o1 > o2 ? -1:1);
        /*System.out.println(list);*/
        /*Collections.sort(list,(o1, o2) -> {
            if(o1 > o2)
            {
                return  -1;
            }
            else if(o1 < o2)
            {
                return  1;
            }
            else
            {
                return  0;
            }
        });*/
        //只有改变o1和o2的顺序即可改变倒序和正序
//        Collections.sort(list,(o1,o2)->{return Integer.compare(o2,o1);});
        //当函数体/方法体中只有一个return语句时,return和大括号都可以省略
        Collections.sort(list,(o1,o2)->Integer.compare(o2,o1));
        System.out.println(list);
    }

    /**
     * 练习:
     * 	使用Lambda表达式的方式,分别对Map集合进行倒序排序。
     */
    @Test
    public void mapDemo()
    {
//        TreeMap<Integer,String> tm = new TreeMap<>((o1,o2)->Integer.compare(o2,o1));
        TreeMap<Integer,String> tm = new TreeMap<>((o1, o2) -> {
            if(o1 > o2)
            {
                return  -1;
            }
            else if(o1 < o2)
            {
                return  1;
            }
            else
            {
                return  0;
            }
        });
        tm.put(23,"tom");
        tm.put(2,"jim");
        tm.put(13,"tim");
        tm.put(26,"lilei");
        tm.put(36,"hanmm");
        tm.put(62,"lucy");
        System.out.println(tm);
    }

}

语法糖

Lambda 方法引用,Lambda 表达式的语法糖。
格式:
类 :: 要引用的方法

函数式接口

package com.wlx.day17;

@FunctionalInterface
public interface FntInterface2
{
    public int  bjq(Integer a,Integer b);
}

自定义类

package com.wlx.day17;

public class MyInteger
{
    public static  int myCompare(Integer c,Integer d)
    {
        return  c + d;
    }
}

Lambda 表达式语法糖实现

@Test
    public  void  test1()
    {
        FntInterface2  fnt2 = (a,b) -> Integer.compare(a,b);
        //调用fnt2对象中的bjq()方法,具体返回的结果是根据Lambda表达式的计算结果返回
//        System.out.println(fnt2.bjq(12, 12));
        FntInterface2  ft = Integer :: compare;
        //调用ft对象中的bjq()方法,具体返回的结果是根据Lambda表达式的计算结果返回
//        System.out.println(ft.bjq(12, 12));


        FntInterface2  fn = (a,b) -> MyInteger.myCompare(a,b);
        /*
        调用fn对象中的bjq()方法,具体返回的结果是根据Lambda表达式的计算结果返回
        即返回myCompare()方法的结果
         */
        System.out.println(fn.bjq(2, 3));
        /*
        调用nt对象中的bjq()方法,具体返回的结果是根据Lambda表达式的计算结果返回
        即返回myCompare()方法的结果
         */
        FntInterface2  nt = MyInteger::myCompare;
        System.out.println(nt.bjq(3, 3));
    }

方法引用

方法引用其实就是 Lambda 表达式的一个语法糖。
要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致。
操作符: :: , 使用该操作符将类或对象与方法分隔开来。
格式一:
对象名 :: 实例方法名
格式二:
类名 :: 静态方法名
格式三:
类名 :: 实例方法名

1.1、对象名 :: 实例方法名

方法引用使用的要求: 要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同。

函数式接口 1

package com.wlx.day17;

@FunctionalInterface
public interface MyLambdaInterface
{
    public  int  compre(String s,String t);
}

函数式接口 2

package com.wlx.day17;

public interface MyLambdaFace
{
    public  void shuchu(String str);
}

自定义类

package com.wlx.day17;

public class MyLambdaClass
{
    public  int  copa(String s,String t)
    {
        return  s.length()+t.length();
    }



}

测试方法

 @Test
    public  void  test2()
    {
        MyLambdaClass  mlc = new MyLambdaClass();

        MyLambdaInterface  mli = mlc :: copa;

        /*
        调用函数式接口中的compre(),并传递参数,返回mlc对象对应的copa()
        计算以后的结果
         */
        System.out.println(mli.compre("hello","world"));
    }


    @Test
    public  void  test3()
    {
        PrintStream ps = System.out;

        MyLambdaFace  mlf = ps :: println;

        /*
        调用函数式接口中的shuchu(),并传递参数,输出结果是ps对象对应的println()
        处理以后的结果
         */
        mlf.shuchu("hello System.out.println");
    }

优化支持多种类型

接口:

package com.wlx.day17;

public interface MyLambdaFace<T>
{
    public  void shuchu(T t);
}

测试类

@Test
    public  void  test3()
    {

        PrintStream ps = System.out;

        MyLambdaFace<Object>  mlf = ps :: println;

        /*
        调用函数式接口中的shuchu(),并传递参数,输出结果是ps对象对应的println()
        处理以后的结果
         */
        mlf.shuchu("hello System.out.println");

        mlf.shuchu(123);

        mlf.shuchu(new Users());

        //使用Oracle提供的函数式接口
        Consumer  con = ps :: println;
        con.accept("hello Consumer---");
        con.accept(321);
        con.accept(new Users());


    }

1.2、类::静态方法名

抽象方法和静态方法参数列表和返回值类型一样时使用。
测试方法

@Test
    public  void  test4()
    {
        /*
        使用Oracle提供的函数式接口Function,返回的结果同样是
        myCompare2()方法返回的结果
         */
        Function<Integer,Integer>  ft = MyInteger::myCompare2;
        Integer it = ft.apply(123);
        System.out.println(it);
    }

使用 Oracle 提供的 Function 接口

自定义方法

public static  String  hqString(Users users)
    {
        return users.getUsername()+ users.getUserpwd();
    }

测试方法

@Test
    public  void  test5()
    {
        Users  users = new Users(1,"tom","tom123",23,"男");
        Function<Users,String>  fnt = MyInteger::hqString;
        //打印获取hqString()方法返回的结果值
        System.out.println(fnt.apply(users));
    }

1.3、类::实例方法名

自定义函数式接口时,第一个形参要和语法糖中的类名一致,后面的形参用于传递给调用的实例方法,并且函数式接口中的形参个数和类名中方法形参个数始终保持一个形参的相差,接口形参大于类中形参个数。
自定义函数式接口

package com.wlx.day17;

public interface MyFunction
{
    public String getUser(Users users,String s);
}

自定义类

package com.wlx.day17;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Users
{
    private Integer uid;
    private String username;
    private String userpwd;
    private Integer userage;
    private String usersex;

    public String hqUsers()
    {
        return  username+"\t"+userpwd;
    }

    public String hqUsers2(String str)
    {
        return  username+"\t"+userpwd+"\t"+str;
    }

}

测试方法

@Test
    public  void  test6()
    {
        com.wlx.day17.Users  users = new com.wlx.day17.Users(1,"jim","jim123",23,"男");
        Function<com.wlx.day17.Users,String>  fnt = com.wlx.day17.Users::hqUsers;
        //打印获取hqUsers()方法返回的结果值
        //System.out.println(fnt.apply(users));

        /*Comparator<String>  com = String::compareTo;
        System.out.println(com.compare("hello","hello"));*/

        MyFunction  mf = com.wlx.day17.Users::hqUsers2;
        //第一个参数users和Users类型一致,字符串"haha"传递给hqUsers2(),
        // 最终结果返回的是hqUsers2()方法返回的结果
        System.out.println(mf.getUser(users, "haha"));
    }

构造方法引用

构造方法引用和普通方法引用类似,函数式接口的抽象方法的形参列表和构造方法的形参列表一致;抽象方法的返回值类型即为构造方法所属的类的类型。
函数式接口的泛型,最后一个泛型类型是构造方法所属的类型,前面的泛型都是构造方法的形参类型,按照顺序排列接口。
格式:
类名 :: new

 /**
     * 无参数的构造方法的使用
     */
    @Test
    public  void  test7()
    {
        //使用Oracle提供的函数式接口
        Supplier<Users>  sup = new Supplier<Users>() {
            @Override
            public Users get() {
                return new Users();
            }
        };

        System.out.println("---"+sup.get());

        //Lambda表达式使用
        Supplier<Users>  supp = () -> new Users();
        System.out.println("==="+supp.get());
        //语法糖使用
        Supplier<Users> suppli = Users::new;
        System.out.println("***"+suppli.get());
    }

    /**
     * 有一个参数的构造方法调用
     */
    @Test
    public void  test8()
    {
        //该函数式接口的泛型,第二个泛型类型是构造方法对应类的类型,
        // 第一个泛型类型是为构造方法传递参数的类型
        Function<String, com.wlx.day17.Users> fnt = com.wlx.day17.Users::new;
        //此处调用Function接口中的apply(),参数是给构造方法传递参数,返回的值是Users对象
        System.out.println(fnt.apply("tomjimlilei"));
    }

自定义函数式接口—无泛型

package com.wlx.day17;

public interface MyFunction2
{
    public Users hqUsers6(Integer uid,String username,String userpwd,Integer userage,String usersex);
}

测试方法

/**
     * 无泛型的方式
     */
    @Test
    public void  test9()
    {
        MyFunction2  mf = com.wlx.day17.Users::new;

        System.out.println(mf.hqUsers6(16, "shenteng", "st123", 23, "男"));


    }

自定义函数式接口—有泛型

package com.wlx.day17;

/**
 *
 * @param <E1>构造方法第一个参数类型
 * @param <E2>构造方法第二个参数类型
 * @param <E3>构造方法第三个参数类型
 * @param <E4>构造方法第四个参数类型
 * @param <E5>构造方法第五个参数类型
 * @param <T>最后一个泛型是构造方法所属的类型
 */
public interface MyFunction3<E1,E2,E3,E4,E5,T>
{
    public T hqUsers6(E1 uid,E2 username,E3 userpwd,E4 userage,E5 usersex);
}

测试方法

/**
     * 有泛型
     */
    @Test
    public void  test10()
    {
        MyFunction3<Integer,String,String,Integer,String,com.wlx.day17.Users>  mf = com.wlx.day17.Users::new;

        System.out.println(mf.hqUsers6(16, "shenteng", "st123", 23, "男"));


    }

数组的引用

数组的引用和构造方法一样。

@Test
    public void test11()
    {
        //Lambda表达式使用
        Function<Integer,String[]>  ft = length -> new String[length];

        String[]  st = ft.apply(3);
        st[0] = "tom";
        st[1] = "jim";
        st[2] = "lilei";
        System.out.println(Arrays.toString(st));


        //语法糖的使用
        Function<Integer,String[]> fnt = String[]::new;
        String[]  str = ft.apply(3);
        str[0] = "hanmm";
        str[1] = "lihua";
        str[2] = "lucy";
        System.out.println(Arrays.toString(str));
    }

Stream

集合关注的是数据的存储,与内存打交道。
Stream 关注的是对数据的运算,与 CPU 打交道。
注意:
1、Stream 自己不会存储元素
2、Stream 不会改变源对象,相反它们会返回一个持有结果的新 Stream。
3、Stream 操作是延迟执行的,这意味着他们会等到需要结果的时候才运行。

1.1、Stream 执行流程

1、Stream 的实例化,即创建 Stream
一个数据源(集合,数组),获取一个流。
2、一系列的中间操作。
中间操作链,对数据源的数据进行处理。
3、终止操作。
一旦执行终止操作,就执行中间操作链,并产生结果,之后,不会在被使用,如果要再次使用,必须重新创建对象。

1.2、创建 Stream

1.2.1、通过 Collection 创建对象

创建 Stream 方式一:
JDK8 中的 Collection 接口。

@Test
    public  void  test1()
    {
        List<Users> list = new ArrayList<>();
        //创建Stream对象
        Stream<Users> st = list.stream();
        //创建Stream对象
        Stream<Users> tem = list.parallelStream();
    }

1.2.3、通过 Stream 的 of()创建

创建 Stream 方式三:
可以调用 Stream 类的静态方法 of(),通过显示值创建一个 Stream,它可以接收任意数量的参数。

public  void test3()
    {
      Stream<Integer>  stream = Stream.of(1,2,3,4,5,6);
    }

1.2.4、创建 Stream 的 iterate()和 generate()

Stream 的 iterate()和 generate()创建一个无限的 Stream 对象。

@Test
    public void  test4()
    {
        //PrintStream ps = System.out;
        //遍历10个偶数值,从0开始加2得到10个
        Stream.iterate(0,t -> t + 2).limit(10).forEach(System.out::println);
        //随机生成6个数值
        Stream.generate(Math::random).limit(6).forEach(System.out::println);

    }

1.3、中间操作

多个中间操作可以连接起来行一个 Stream 流水线,除非流水线上触发终止操作,否则中间操作不会执行任何处理,而在终止操作时一次性全部处理,这样处理方式称为"惰性求值"。

1.3.1、筛选与切片

@Test
    public  void  test5()
    {
        List<Users>  list = getUsers();
        //创建Stream对象
        Stream<Users>  stream = list.stream();
        //筛选人员信息年龄大于23的人员信息
        stream.filter(users -> users.getUserage() > 23).forEach(System.out::println);
        System.out.println("-------------");
        //筛选人员信息年龄大于25的人员信息
        //此处运行出错,因为上面筛选完年龄大于23的人员信息后,该stream就已经终止操作了,如果要再次使用
        //则必须重新创建Stream对象
        //stream.filter(users -> users.getUserage() > 25).forEach(System.out::println);
        list.stream().filter(users -> users.getUserage() > 25).forEach(System.out::println);
    }
  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值