前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java8新特性----Lambda表达式详细探讨

Java8新特性----Lambda表达式详细探讨

作者头像
大忽悠爱学习
发布2021-11-15 15:11:01
2550
发布2021-11-15 15:11:01
举报
文章被收录于专栏:c++与qt学习c++与qt学习

Java8新特性


Lambda表达式

​ Lambda是一个匿名函数,可以理解为一段可以传递的代码(将代码像数据一样传递);可以写出更简洁、更灵活的代码;作为一种更紧凑的代码风格,是Java语言表达能力得到提升


入门演示

案例1

代码语言:javascript
复制
public class TestMain
{
    //使用匿名内部类完成比较
    @Test
    public void test()
    {
        //比较器                 匿名内部类,创建该接口的一个实现类
        Comparator<People> com=new Comparator<People>() {
            @Override
            public int compare(People o1, People o2) {
                return o1.getAge()-o2.getAge();
            }
        };
        //TreeSet的特点是可排序、不重复
        TreeSet<People> ts=new TreeSet<>(com);
        ts.add(new People("大忽悠",20));
        ts.add(new People("小忽悠",18));
        ts.add(new People("大大大",22));
        ts.add(new People("小朋友",17));
        ts.forEach(System.out::println);
    }

    //lambda表达式替代匿名内部类
    @Test
    public void test1()
    {
        //比较器
        Comparator<People> com=(p1,p2)-> p1.getAge()-p2.getAge();
        //TreeSet的特点是可排序、不重复
        TreeSet<People> ts=new TreeSet<>(com);
        ts.add(new People("大忽悠",20));
        ts.add(new People("小忽悠",18));
        ts.add(new People("大大大",22));
        ts.add(new People("小朋友",17));
        ts.forEach(System.out::println);
    }
}
在这里插入图片描述
在这里插入图片描述

如何解决 cannot be cast to java.lang.Comparable问题?

如何解决 cannot be cast to java.lang.Comparable问题?


案例2

要求对下面的代码进行优化:

代码语言:javascript
复制
public class TestMain
{
    List<People> peopleList= Arrays.asList(
            new People("1号",18,3000),
            new People("2号",21,4000),
            new People("3号",19,5000),
            new People("4号",20,3500)
    );
    //获取年龄大于18的
    public List<People> getAgeOver18()
    {
        List<People> list=new ArrayList<>();
        for (People p:peopleList)
        {
            if(p.getAge()>18)
                list.add(p);
        }
        return list;
    }

    //获取工资大于3000的
    public List<People> getMoneyOver3000()
    {
        List<People> list=new ArrayList<>();
        for (People p:peopleList)
        {
            if(p.getMoney()>3000)
                list.add(p);
        }
        return list;
    }
    @Test
    public void test()
    {
        List<People> ageOver18 = getAgeOver18();
        ageOver18.forEach(System.out::println);
        System.out.println("======================================");
        List<People>  moneyOver3000=getMoneyOver3000();
        moneyOver3000.forEach(System.out::println);
    }
}

优化方式一 : 策略设计模式

声明一个接口MyPrediect

代码语言:javascript
复制
public interface MyPrediect<T>
{
  public boolean test(T t);
}

接口的实现类一FilterPeoAge,负责过滤年龄:

代码语言:javascript
复制
public class FilterPeoAge implements MyPrediect<People>{
    @Override
    public boolean test(People people) {
        return people.getAge()>18;
    }
}

接口实现类二FilterPeoMoney,负责过滤金钱

代码语言:javascript
复制
public class FilterPeoMoney implements MyPrediect<People>{
    @Override
    public boolean test(People people) {
        return people.getMoney()>3000;
    }
}

测试演示:

代码语言:javascript
复制
public class TestMain
{
    List<People> peopleList= Arrays.asList(
            new People("1号",18,3000),
            new People("2号",21,4000),
            new People("3号",19,5000),
            new People("4号",20,3500)
    );
     public List<People> FilterPeo(List<People> list,MyPrediect<People> mp)
     {
         List<People> peopleList=new ArrayList<>();
         for (People p:list)
         {
             if(mp.test(p))
                 peopleList.add(p);
         }
         return peopleList;
     }

    @Test
    public void test()
    {
        List<People> peopleList = FilterPeo(this.peopleList, new FilterPeoAge());
        peopleList.forEach(System.out::println);
        System.out.println("===========================");
        List<People> peopleList1 = FilterPeo(peopleList, new FilterPeoMoney());
        peopleList1.forEach(System.out::println);
    }
}
在这里插入图片描述
在这里插入图片描述

当我们还需要安装某个策略进行过滤时,只需要实现接口,完成相应策略过滤逻辑编写即可


优化方式二: 策略设计模式+匿名内部实现接口,减少创建实体类的麻烦

代码语言:javascript
复制
public class TestMain
{
    List<People> peopleList= Arrays.asList(
            new People("1号",18,3000),
            new People("2号",21,4000),
            new People("3号",19,5000),
            new People("4号",20,3500)
    );
     public List<People> FilterPeo(List<People> list,MyPrediect<People> mp)
     {
         List<People> peopleList=new ArrayList<>();
         for (People p:list)
         {
             if(mp.test(p))
                 peopleList.add(p);
         }
         return peopleList;
     }

    @Test
    public void test()
    {
        List<People> peopleList = FilterPeo(this.peopleList, new MyPrediect<People>() {
            @Override
            public boolean test(People people) {
                return people.getAge()>18;
            }
        });
        peopleList.forEach(System.out::println);
        System.out.println("===========================");
        List<People> peopleList1 = FilterPeo(peopleList, new MyPrediect<People>() {
            @Override
            public boolean test(People people) {
                return people.getMoney()>3000;
            }
        });
        peopleList1.forEach(System.out::println);
    }
}
在这里插入图片描述
在这里插入图片描述

优化方式三: lambda表达式

代码语言:javascript
复制
public class TestMain
{
    List<People> peopleList= Arrays.asList(
            new People("1号",18,3000),
            new People("2号",21,4000),
            new People("3号",19,5000),
            new People("4号",20,3500)
    );
     public List<People> FilterPeo(List<People> list,MyPrediect<People> mp)
     {
         List<People> peopleList=new ArrayList<>();
         for (People p:list)
         {
             if(mp.test(p))
                 peopleList.add(p);
         }
         return peopleList;
     }

    @Test
    public void test()
    {
        List<People> peopleList = FilterPeo(this.peopleList, (people)-> people.getMoney()>4000);
        peopleList.forEach(System.out::println);
    }
}
在这里插入图片描述
在这里插入图片描述

优化方式四: stream流

代码语言:javascript
复制
public class TestMain
{
    List<People> peopleList= Arrays.asList(
            new People("1号",18,3000),
            new People("2号",21,4000),
            new People("3号",19,5000),
            new People("4号",20,3500)
    );
     public List<People> FilterPeo(List<People> list,MyPrediect<People> mp)
     {
         List<People> peopleList=new ArrayList<>();
         for (People p:list)
         {
             if(mp.test(p))
                 peopleList.add(p);
         }
         return peopleList;
     }

    @Test
    public void test()
    {
        peopleList.stream().filter(people -> people.getMoney()>3000).limit(2).forEach(System.out::println);
    }
}
在这里插入图片描述
在这里插入图片描述

Lambda语法

代码语言:javascript
复制
- 操作符:->
- 左侧:参数列表
- 右侧:执行代码块 / Lambda 体
在这里插入图片描述
在这里插入图片描述

即lambda是对接口的抽象方法的实现,可能有人会问,如果接口中抽象方法存在多个,那lambda是对哪个抽象方法的实现呢?

其实lambda需要一个函数式接口的支持,即当前接口只有一个抽象方法


语法格式一 : 无参数,无返回值

代码语言:javascript
复制
    @Test
  public void test()
  {
      Runnable runnable = new Runnable() {
          @Override
          public void run() {
              System.out.println("方法执行中.....");
          }
      };
      runnable.run();
      System.out.println("----------------------");
      Runnable r1=()-> System.out.println("r1执行中....");
      r1.run();
  }
在这里插入图片描述
在这里插入图片描述

注意: 局部内部类与局部变量

局部内部类在JDK8之前只能使用成员变量和被final修饰的局部变量。JDK8之后,局部内部类如果使用局部变量那么局部变量默认被final修饰,但如果局部变量被重新赋值,那么局部内部类将不能在使用。具体看下例子:

代码语言:javascript
复制
	public void show() {
		int j = 0;   //jdk1.8后默认被final修饰。1.8之前局部内部类只能访问成员变量,和被final修饰的局部变量
		class A{
			public void showA() {
				System.out.println(i);
				System.out.println(j);
			}
		}
//		j = 2;//如果对局部变量做了修改,则默认会变成不被final修饰。局部内部类不可调用
	}

//注:有静态成员的一定是静态内部类

lambda这里跟匿名内部类用法一致


语法格式二: 有一个参数,无返回值

代码语言:javascript
复制
public class TestMain
{
    @Test
  public void test()
  {
      Consumer<String> consumer=(x)-> System.out.println(x);
      //  void accept(T t); 对该抽象方法进行实现
      consumer.accept("大忽悠");
  }
}
在这里插入图片描述
在这里插入图片描述

语法格式三: 如果一个参数,那么小括号可以不写

代码语言:javascript
复制
      Consumer<String> consumer=x-> System.out.println(x);
      //  void accept(T t); 对该抽象方法进行实现
      consumer.accept("大忽悠");

语法格式四:有两个参数,有返回值,lambda体中有多条语句

代码语言:javascript
复制
public class TestMain
{
    @Test
  public void test()
  {
      //   int compare(T o1, T o2);重写该方法
      Comparator<Integer> com=(x,y)->{
          System.out.println("函数式接口");
          return Integer.compare(x,y);
      };
      int compare = com.compare(1, 2);
      System.out.println(compare);
  }
}
在这里插入图片描述
在这里插入图片描述

语法格式五:若lambda体中只有一条语句,那么return和{}都可以省略不写

代码语言:javascript
复制
  public void test()
  {
      //   int compare(T o1, T o2);重写该方法
      Comparator<Integer> com=(x,y)->Integer.compare(x,y);
      int compare = com.compare(1, 2);
      System.out.println(compare);
  }

语法格式六: lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,即“类型推断”


Lambda需要函数式接口的支持

函数式接口: 接口中只有一个抽象方法的接口,称为函数式接口,可以使用@FunctionalIterface修饰,检查当前接口是否式函数式接口

我们可以通过lambda来实现函数式接口里面的唯一的抽象方法


举例一

代码语言:javascript
复制
public class TestMain
{
    List<People> peopleList= Arrays.asList(
            new People("1号",18,3000),
            new People("2号",20,4000),
            new People("3号",18,5000),
            new People("4号",20,3500)
    );
     //先安装年龄升序排序,年龄相同,再安装money降序排序
    @Test
    void test()
    {
        //重写下面这个方法,比较器可以为空
        //    public static <T> void sort(List<T> list, Comparator<? super T> c) {
        //        list.sort(c);
        //    }
        Collections.sort(peopleList,(p1,p2)->{
            if(p1.getAge()==p2.getAge())
                return -p1.getMoney().compareTo(p2.getMoney());
            else
                return p1.getAge().compareTo(p2.getAge());
        });
        peopleList.forEach(System.out::println);
    }
}
在这里插入图片描述
在这里插入图片描述

涉及知识点一: Interage.compareTo()
代码语言:javascript
复制
Integer obj2=100;
  //比较大小
        System.out.println(obj2.compareTo(100));
        System.out.println(obj2.compareTo(102));
        System.out.println(obj2.compareTo(10));

结果: 0 , -1 , 1 ,即大于返回 1 ,小于返回 -1 ,等于返回 0


涉及知识点二: Collections工具类

详细用法


内置四大核心函数式接口

代码语言:javascript
复制
Consumer<T> :消费型接口

void  accept(T t);

Supplier<T>:供给型接口

T get(T t);

Function<T,R>:函数型接口

R apply(T t);

Predicate<T>:断言型接口

boolean test(T t);

Consumer :消费型接口

代码语言:javascript
复制
@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
}

测试:

代码语言:javascript
复制
public class TestMain
{
    @Test
    void test()
    {
                     //这里的lambda表达式实现了对应的抽象函数
          happy(10000,(m)-> System.out.println("我有: "+m));
    }
    public void happy(Integer money,Consumer<Integer> com)
    {
        com.accept(money);
    }
}
在这里插入图片描述
在这里插入图片描述

Supplier:供给型接口

代码语言:javascript
复制
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

测试:

代码语言:javascript
复制
public class TestMain
{
    @Test
    void test()
    {
         List<String> numList=getNumList(5,()->UUID.randomUUID().toString().substring(0,8));
         numList.forEach(System.out::println);
    }
     //需求: 产生指定个数的随机id,并放入集合中
    public List<String> getNumList(int num, Supplier<String> supplier)
    {
        ArrayList<String> integers = new ArrayList<String>();
        for(int i=0;i<num;i++)
        {
            integers.add(supplier.get());
        }
        return  integers;
    }
}
在这里插入图片描述
在这里插入图片描述

Function<T,R>: 函数型接口

代码语言:javascript
复制
public interface Function<T, R>{
    R apply(T t);
    }

测试:

代码语言:javascript
复制
public class TestMain
{
    @Test
    void test()
    {
       String str=StrHandler("\t\t\t    大忽悠    \t\t\t",(s)->s.trim());
        System.out.println(str);
    }
    //需求: 处理字符串
      public String StrHandler(String str, Function<String,String> f)
      {
          return f.apply(str);//返回被处理过后的字符串
      }
}
在这里插入图片描述
在这里插入图片描述
涉及知识点: trim()函数

trim()方法的使用


Predicate:断言型接口

代码语言:javascript
复制
@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
    }

测试:

代码语言:javascript
复制
public class TestMain
{
    @Test
    void test()
    {
           StrHandler("大忽悠啊",(str)->str.length()>3);
        StrHandler("嘿嘿",(str)->str.length()>3);
    }
    //需求: 处理字符串
      public void StrHandler(String str, Predicate<String> predicate)
      {
           if(predicate.test(str))
               System.out.println(str);
           else
               System.out.println("太短了");
      }
}
在这里插入图片描述
在这里插入图片描述

其他常用函数式接口

在这里插入图片描述
在这里插入图片描述

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-08-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java8新特性
  • Lambda表达式
  • 入门演示
    • 案例1
      • 如何解决 cannot be cast to java.lang.Comparable问题?
    • 案例2
      • 优化方式一 : 策略设计模式
      • 优化方式二: 策略设计模式+匿名内部实现接口,减少创建实体类的麻烦
      • 优化方式三: lambda表达式
      • 优化方式四: stream流
  • Lambda语法
    • 语法格式一 : 无参数,无返回值
      • 注意: 局部内部类与局部变量
    • 语法格式二: 有一个参数,无返回值
      • 语法格式三: 如果一个参数,那么小括号可以不写
        • 语法格式四:有两个参数,有返回值,lambda体中有多条语句
          • 语法格式五:若lambda体中只有一条语句,那么return和{}都可以省略不写
            • 语法格式六: lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,即“类型推断”
              • Lambda需要函数式接口的支持
                • 函数式接口: 接口中只有一个抽象方法的接口,称为函数式接口,可以使用@FunctionalIterface修饰,检查当前接口是否式函数式接口
                • 我们可以通过lambda来实现函数式接口里面的唯一的抽象方法
                • 举例一
              • 内置四大核心函数式接口
                • Consumer :消费型接口
                • Supplier:供给型接口
                • Function<T,R>: 函数型接口
                • Predicate:断言型接口
              • 其他常用函数式接口
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档