java8新特性--函数式接口+lambda表达式+方法引用


java8出来这么久了,对它还是不熟悉,这不,最近开始学习了,写点学习笔记


什么是函数式接口

  • 只包含一个抽象方法的接口,称为函数式接口
  • 我们可以在一个接口上使用 @FunctionalInterface注解,这样做可以检查它是否是一个函数式接口
  • 有什么用?Lambda表达式就是一个函数式接口的实例,所以以前用匿名实现类表示的现在都可以用Lambda表达式来写
  • 例如Runnable接口就是个函数式接口:
@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

lambda表达式初体验

// 以前实现Runnable接口创建线程这么写
 Runnable r1 = new Runnable() {
     @Override
     public void run() {
         System.out.println("线程run方法。。。。");
     }
 };
 new Thread(r1).start();
// 用lambda表达式可以这么写
 Runnable r2 = ()-> System.out.println("线程run方法。。。。");
 new Thread(r2).start();

怎么样?是不是感觉很神奇,很简洁。

再回到函数式接口

下面一起来了解下Java 内置的四大核心函数式接口:

函数式接口参数类型返回类型用途
Consumer< T >Tvoid对类型为T的对象进行操作,方法为void accept(T t)
Supplier< T >voidT直接返回类型为T的对象,方法为T get()
Function<T,R>TR操作T类型的对象,返回R类型的结果,方法为R apply(T t)
Predicate< T >Tboolean操作T类型的对象,返回布尔值,方法为boolean test(T t)

以上这四种最基本的函数式接口最好能记住,其他函数式接口基本上都是在它们的基础之上来衍生的。

lambda表达式的几种形式

  1. 无参无返回值
Runnable r = ()->{System.out.println("hello lambda!")};
//方法的实现只有一句话时,中括号可以省略
Runnable r = ()->System.out.println("hello lambda!");
  1. 有一个参数无返回值
Consumer<String> c = (String str)->{System.out.println(str);};
//参数类型可以省略,因为有类型推断,只有一个参数时,小括号可以省略
Consumer<String> c = str-> System.out.println(str);
  1. 两个或以上参数,多条执行语句,有返回值
Comparator<Integer> c =(m,n)->{
    System.out.println(m+n);
    return Integer.compare(m,n);
};
  1. 有参数有返回值,一条执行语句
Function<Integer,String> f = i -> {
    return i+"";
};
//此时,return和大括号可以省略
Function<Integer,String> f = i -> i+"";

方法引用

我们通常使用lambda表达式来创建匿名方法。然而,有时候我们仅仅是调用了一个已存在的方法,此时就可以用方法引用。


先写一个person类,用于测试

public class Person {
    String name;
    Integer age;
    public static String getSth(Integer i){
        return "hello"+i;
    }
    public Person() {
    }
    public Person(String name) {
        this.name = name;
    }
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    //  get/set 

情况1:对象调用非静态方法 对象::方法名
 Consumer<String> con1 = con -> System.out.println(con);
 con1.accept("hello con1");
/* 可以发现 
       Consumer 中的 void accept(T t); 
  与   PrintStream 中的 void println(String x) 结构差不多,所以,可以这样写:
*/  
 PrintStream p = System.out;
 Consumer<String> con2 = p::println;
 con2.accept("hello con2");
// 再来一个
 Person person = new Person("吴邪");
 
 Supplier<String> sup1 = () -> person.getName();
 System.out.println(sup1.get());
/*
   Supplier 中 T get() 
与 Person  中 String getName() 形式是类似的
*/
 Supplier<String> sup2 = person::getName;
 System.out.println(sup2.get());

情况2:类调用静态方法 类::静态方法
 Comparator<Integer> com1 = (o1,o2) -> Integer.compare(o1,o2);
 System.out.println(com1.compare(5, 3));
/*
    Comparator 的 int compare(T o1, T o2) 
与  Integer  的 static int compare(int x, int y) 方法的形式类似,故可以这样写
*/
 Comparator<Integer> com2 = Integer::compare;
 System.out.println(com2.compare(9, 9));

// 再来一个
 Function<Integer,String> fun2 = in -> "hello"+in;
 System.out.println(fun2.apply(3));
/*
    同理,发现 Function 的 R apply(T t) 与我们自定义Person类中的 String getSth(Integer i)的结构类似,所以,可以用方法引用
*/ 
 Function<Integer,String> fun3 = Person::getSth;
 System.out.println(fun3.apply(5));

情况3:类调用非静态方法 类::非静态方法 (有难度)
 Comparator<String> comparator1 = (o1,o2)->o1.compareTo(o2);
 System.out.println(comparator1.compare("abc", "abe"));
/*      
 这次和之前的有些不同,我们把
     Comparator 的 int compare(T o1, T o2)
 与  String  的非静态方法 int o1.compareTo(o2) 拿来对应
 把compare中的o1作为compareTo方法的调用者,把o2作为compareTo方法的参数
 不是很好理解,可以自己多写写,多体会一下
*/
 Comparator<String> comparator2 = String::compareTo;
 System.out.println(comparator2.compare("bcd", "bca"));
 
 //再来一个例子
 Person person = new Person("胖子");
 
 Function<Person,String> func1 = p -> p.getName();
 System.out.println(func1.apply(person));
/*
 同样,去对比
     Function 的 R apply(T t)
 与  Person   的 String t.getName()
 我们把apply方法的参数t作为getName方法的调用者,没有参数
*/
 Function<Person,String> func2 = Person::getName;
 System.out.println(func2.apply(person));
 
情况4:构造器引用与数组引用 类::new 数组::new
//1.无参
 Supplier<Person> s1 = ()->new Person();
 Supplier<Person> s2 = Person::new;
//2.一个参数
 Function<String,Person> f1 = str -> new Person(str);
 Function<String,Person> f2 = Person::new;
 Person p = f2.apply("小哥");
 System.out.println(p.getName());
//3.两个参数 
 BiFunction<Integer,String,Person> bi1 = (i,s)->new Person(s,i);
 BiFunction<String,Integer,Person> bi2 = Person::new;
 Person xiaobai = bi2.apply("小白", 18);
 System.out.println(xiaobai.getName()+":"+xiaobai.getAge());
/*
 综上,应该发现,无论如何都调用的是 Person::new 因为,方法引用不能传递参数,
 那么,参数是如何体现的呢?就是通过前面那个函数式接口的泛型类型和个数体现的
*/
//4.数组引用,与构造器引用类似
 Function<Integer,String[]> fun1 = i -> new String[i];
 String[] strArr1 = fun1.apply(4);
 System.out.println(strArr1.length);
 
 Function<Integer,String[]> fun2 = String[]::new;
 String[] strArr2 = fun2.apply(3);
 System.out.println(strArr2.length);


写在最后:
语法不是逻辑,想不通很正常,多写写,多用用,然后就接受了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值