01.java8入门 函数式编程的不变模式 FunctionalInterface注解 接口的默认方式--default关键字


import java.util.Arrays;

/**
 * 函数式编程的不变模式
 */
public class ArrStream {
    public static void main(String[] args){
        int[] arr = {1,2,3,4,5};
        Arrays.stream(arr).map((x)->x+1).forEach(System.out::print);
        System.out.println();
        Arrays.stream(arr).forEach(System.out::print);
    }
    //23456
    //12345
}

FunctionalInterface注解

/**
 * FunctionalInterface注解
 */
@FunctionalInterface //用于表明是一个函数式接口
public  interface IntHandler {
    void handle(int i);//只包含一个抽象方法
}
@FunctionalInterface //用于表明是一个函数式接口
public  interface IntHandler {
    boolean equals(Object obj);//此时编译未通过,不是函数式接口,因为equals()方法在java.lang.Object中已经实现
}
/**
 * 符合函数式接口要求
 */
@FunctionalInterface //用于表明是一个函数式接口
public  interface IntHandler {
    boolean equals(Object obj);
    void handle(int i);
}

接口的默认方式--default关键字

public interface IHorse {
    void eat();
    //使用default关键字,可以在接口内定义实例方法
    default void run(){
        System.out.println("Horse run");
    }
}
public interface IAnimal {
    default void breath(){
        System.out.println("breath");
    }
}
public interface IDonkey {
    void eat();
    default void run(){
        System.out.println("Donkey run");
    }
}

/**
 * 同时拥有不同接口的实现方法
 */
public class Mule implements IAnimal,IHorse,IDonkey {
    @Override
    public void eat() {
        System.out.println("Mule eat");
    }
    @Override
    public void run(){
        IHorse.super.run();
    }
    public static void main(String[] args){
        Mule mule = new Mule();
        mule.run();
        mule.breath();
    }
    //Horse run
    //breath
}

import java.util.function.Function;

/**
 * lambda表达式访问外部的局部变量
 */
public class LambdaTest {
    public static void main(String[] args){
        final int num = 2;//外部的变量必须申明为final,即使省略final也可以编译通过,这是因为Java8会自动将lambda表达式中使用的变量视为final
        Function<Integer,Integer> st = (from)->from*num;
        System.out.println(st.apply(3));
        int num2 = 3;
        Function<Integer,Integer> st2 = (from)->from*num2;
        num2++;//编译保错 Error:(14, 54) java: 从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量
    }
}

import java.util.ArrayList;
import java.util.List;

/**
 * 方法引用:
 * 静态方法引用:ClassName::methodName
 * 实例上的实例方法引用:instanceReference::methodName
 * 超类上的实例方法引用:super:methodName
 * 类型上的实例方法引用:ClassName::methodName
 * 构造方法引用:Class::methodName
 * 数组构造方法引用:TypeName[]::methodName
 *
 * 方法引用使用::定义,::前半部分表示类名或实例名,后半部分表示方法名称,如果是构造函数,则使用new表示
 */
public class InstanceMethodDemo {
    static class User{
        private int id;
        private String name;

        public User(int id, String name) {
            this.id = id;
            this.name = name;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
    public static void main(String[] args){
        List<User> users = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            users.add(new User(i,"name"+Integer.toString(i)));
        }
        //User::getName,在执行时,java会自动识别流中的元素(这里指User实例)是作为调用目标还是调用方法的参数,
        //显然应该作为调用目标,在这里调用每一个User对象实例的getName()方法,并将这些User的name作为一个新的流,
        //同时,对于这里得到的所有name,使用方法引用System.out::println进行处理。系统会自动判断,流内的元素此时
        //应该作为方法的参数传入,而️不是调用目标

        // 一般来说,如果使用的是静态方法,或者调用目标明确,那么流内的元素会自动作为参数使用。如果函数引用表示
        //实例方法,并且不存在调用目标,那么流内元素就会自动作为调用目标
        users.stream().map(User::getName).forEach(System.out::println);
    }
    //name0
    //name1
    //name2
    //name3
    //name4
    //name5
    //name6
    //name7
    //name8
    //name9
}
import java.util.ArrayList;
import java.util.List;

public class ConstrMethodRef {
    public static void main(String[] args){
        List<User> users = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            users.add(uf.create(i,"name"+Integer.toString(i)));
        }
        users.stream().map(User::getName).forEach(System.out::println);
    }
    //User::new创建接口实例时,系统会根据UserFactory.create()的函数签名来选择合适的User构造函数
    //在这里,很显然就是 public User(int id, String name),在创建UserFactory.create()的调用
    //都会委托给User的实际构造函数进行,从而创建User对象实例。
    static UserFactory<User> uf = User::new;
    @FunctionalInterface
    interface UserFactory<U extends User>{
        U create(int id,String name);
    }
    static class User{
        private int id;
        private String name;

        public User(int id, String name) {
            this.id = id;
            this.name = name;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}