java8新特性lambda表达式

Java8引入的Lambda表达式简化了代码,尤其在处理匿名内部类时。Lambda的基本语法为 () -> {},接口上的@FunctionalInterface注解使得Lambda能重写接口的抽象方法。本文介绍了Lambda的使用,包括参数列表、方法体和引用方法。同时,展示了如何利用Lambda操作数组、创建对象、处理字符串以及在集合操作中的应用。
摘要由CSDN通过智能技术生成

Lambda表达式

简介

Lambda表达式可以取代大部分匿名内部类,可以优化代码结构。

可以取代匿名内部类?什么意思呢?

在以前如果我们需要对集合排序,我们是这样做:

Integer[] arr= {3,2,1};
Arrays.sort(arr, new Comparator<Integer>() {

	@Override
	public int compare(Integer o1, Integer o2) {
		return o1-o2;
	}
});
System.out.println(Arrays.toString(arr));

使用Arrays类提供的sort方法传入一个指定排序规则的Comparator,如果我们使用匿名内部类的话,可以看到整个内部类中只用return o1-o2;语句是有用的,其他的都是多余的,为了这一句话我们多写了很多代码。那么,有了Lambda表达式后我们就可以很轻松的解决这个问题了。

java8中新增了Lambda表达式,现在我们可以这样做:

Integer[] arr= {3,2,1};
Arrays.sort(arr, (x,y)->x-y);
System.out.println(Arrays.toString(arr));

那么Lambda是如何实现的呢?我们知道sort方法需要传入一个Comparator,而Comparator是一个接口,那么我们来看看Comparator接口是怎样定义的:

@FunctionalInterface
public interface Comparator<T> {

Comparator能够支持Lambda表达式的秘密就是类上标注的@FunctionalInterface注解,被这个注解标注的接口只能有一个抽象方法,我们知道我们写Lambda表达式时并没有指定方法,那么当使用Lambda表达式时我们重新的就是这个方法。

Lambda表达式基本语法

语法形式为 () -> {},其中 () 用来描述参数列表,{} 用来描述方法体,-> 为 lambda运算符

  1. 接口无参无返回

    @FunctionalInterface
    interface NoParamNoReturn {
    	void lambda();
    }
    
    @Test
    public void test() {
      NoParamNoReturn noParamNoReturn=()->{System.out.println("No param No return");};
      noParamNoReturn.lambda();
    }
    //如果方法内只有一个语句那么{}可以省略
    @Test
    public void test() {
      NoParamNoReturn noParamNoReturn=()->System.out.println("No param No return");
      noParamNoReturn.lambda();
    }
    
  2. 接口有一个或多个参数无返回

    @FunctionalInterface
    interface OneParamNoReturn{
    	void lambda(int x);
    }
    @Test
    public void test() {
      OneParamNoReturn oneParamNoReturn=(int x)->System.out.println(x);
      oneParamNoReturn.lambda(10);
    }
    //如果方法只有一个参数那么()可以省略
    //方法参数的类型也可以省略,编译器会根据方法参数类型推断
    @Test
    public void test() {
      OneParamNoReturn oneParamNoReturn=x->System.out.println(x);
      oneParamNoReturn.lambda(10);
    }
    
  3. 接口无参数有返回值

    @FunctionalInterface
    interface NoParamHasReturn{
    	int lambda();
    }
    @Test
    public void test() {
      NoParamHasReturn noParamHasReturn=()->{return 10;};
      noParamHasReturn.lambda();
    }
    //当方法只有return语句时,可以省略{}和return
    @Test
    public void test() {
      NoParamHasReturn noParamHasReturn=()->10;
      noParamHasReturn.lambda();
    }
    
  4. 接口有一个或多个参数有返回值

    @FunctionalInterface
    interface HasParamHasReturn{
    	int lambda(int x,int y);
    }
    @Test
    public void test() {
      HasParamHasReturn hasParamHasReturn=(x,y)->x+y;
      hasParamHasReturn.lambda(10, 20);
    }
    

    Lambda表达式引用方法

    我们可以使用lambda表达式把接口快速指向一个已经实现了的方法

    语法:方法归属者::方法名 静态方法的归属者为类名,普通方法归属者为对象

    @FunctionalInterface
    interface HasParamHasReturn{
    	int lambda(int x,int y);
    }
    public class LambdaTest{
      public int add(int x,int y) {
        return x+y;
      }
    //lambda表达式指向对象方法
      @Test public void test() {
        LambdaTest lt=new LambdaTest();
        HasParamHasReturn hasParamHasReturn=lt::add;
        hasParamHasReturn.lambda(10, 20);
      }
      
      public static int sub(int x,int y) {
        return x-y;
      }
    
      //lambda表达式引用静态方法
      @Test
      public void test12() {
        HasParamHasReturn hasParamHasReturn=LambdaTest::sub;
        hasParamHasReturn.lambda(10, 20);
      } 
    }
    

    lambda表达式引用构造函数创建对象

    语法:类名::new;

    class User{
    	String name;
    	int age;
    	
    	public User() {}
    	
    	public User(String name, int age) {
    		super();
    		this.name = name;
    		this.age = age;
    	}
    	
    }
    
    @FunctionalInterface
    interface UserCreatorBlankConstruct{
    	User getUser();
    }
    
    //使用lambda表达式引用构造器
    @Test
    public void test13() {
      UserCreatorBlankConstruct creator1=User::new;
      creator1.getUser();
    }
    
    @FunctionalInterface
    interface UserCreatorParamConstruct{
    	User getUser(String name,int age);
    }
    
    @Test
    public void test13() {
      UserCreatorParamConstruct creator2=User::new;
      creator2.getUser("tom", 20);
    }
    

    java8为我们提供了4个核心的函数式接口

    1. 消费型接口
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
  1. 供给型接口

    @FunctionalInterface
    public interface Supplier<T> {
        T get();
    }
    
  2. 函数型接口

    @FunctionalInterface
    public interface Function<T, R> {
        R apply(T t);
    }
    
  3. 断言型接口

    @FunctionalInterface
    public interface Predicate<T> {
        boolean test(T t);
    }
    

    怎么用呢?

    遍历数组

    @Test
    	public void test() {
    		List<Integer> list=new ArrayList<>();
    		list.add(1);
    		list.add(3);
    		list.add(5);
    		list.add(7);
    		list.forEach(System.out::println);
    	}
    

    创建对象

    @Test
    public void test() {
      Supplier<User> supplier=User::new;
      User user = supplier.get();
    }
    

    去除前后空格并转为大写

    @Test
    public void test16() {
      Function<String, String> fun=s->{s=s.trim();s=s.toUpperCase();return s;};
      String apply = fun.apply(" abCd");
    }
    

    删除集合元素

    @Test
    public void test() {
      List<User> list=new ArrayList<>();
      list.add(new User("tom",20));
      list.add(new User("jack",18));
      list.add(new User("marry",22));
    
      list.removeIf(e->e.getName()=="jack");
    }
    

那如果我们要用内置函数式接口创建对象,怎么做呢?

@Test
public void test() {
  Supplier<User> supplier=User::new;
  User user = supplier.get();
  System.out.println(user);//User [name=null, age=0]
}

那到底使用的是哪个构造器呢?通过输出创建的对象可以发现调用的是无参构造器,即调用构造器参数个数对应Supplier中get方法的参数个数的构造器

那么问题又来了,如果我们要使用两个参数的构造器,那Supplier也不行啊,Function的apply方法也只有一个参数,怎么办?那我们去java.util.function包下找找有没有可以用的接口

@FunctionalInterface
public interface BiFunction<T, U, R> {
    R apply(T t, U u);
}
//使用内置函数式接口创建对象
@Test
public void test20() {
  BiFunction<String,Integer,User> biFunction=User::new;
  User user = biFunction.apply("tom", 20);
  System.out.println(user);//User [name=tom, age=20]
}

四个基本接口参数个数不够用也可以类似的去java.util.function包下找找有没有申明好的函数式接口

最后一个问题,我发现

list.forEach(System.out::println);

遍历List时,使用的forEach的参数Consumer的accept方法是这么写的,我第一个想到的是,out是System的一个内部类,但是当我点进去,发现是这样的

public final static PrintStream out = null;

out是一个静态的成员变量,那我的理解就是System.out其实是一个对象

这样System.out::println的写法其实也就是 对象名::方法名

我是这样理解的,如果错了还请赐教!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值