101-java8新特性(1)-Lambda表达式

java 8 新特性

java 1.8 相对于java 1.7修改了很多地方,增加了很多新特性.
101-java8新特性(1)-Lambda表达式_第1张图片

Lambda表达式

101-java8新特性(1)-Lambda表达式_第2张图片

1.概念及注意事项

Lambda表达式的格式:
Interface in = Lambda表达式.

注意:
1.左边一定是一个接口,抽象类也不行,因为Lambda表达式就是设计来实现这个接口的方法的匿名内部类
2.左边的这个接口一定是只有一个抽象方法的函数式接口.因为如果有多个接口,则这个Lambda表达式则不能区分是实现的哪个抽象方法.
3.这个函数式接口可以用注解@FunctionalInterface修饰.

函数式接口,例如:

@FunctionalInterface
public interface Runnable {
     
    public abstract void run();
}

2.Lambda表达式的语法

java 8 中引入了一个新的操作符 “->” ,该操作符称为箭头操作符或lambda操作符,他把Lambda表达式分成了两部分:

  • 左侧:Lambda 表达式的参数列表
  • 右侧:Lambda 表达式的中所需要执行的功能,及Lambda 体

(1) 无参数,无返回值

  • () -> System.out.println(“哈哈”)
/**
     * 无参无返回值
     */
    @Test
    public void test1() {
     
        Runnable r1 = new Runnable() {
     
            @Override
            public void run() {
     
                System.out.println("haha");
            }
        };
        r1.run();
        System.out.println("-----------");
        //Lambda表达式
        Runnable r2 = () -> System.out.println("哈哈");
        r2.run();
    }

(2) 有1个参数,无返回值

  • (x) -> System.out.println(x)
  • x -> System.out.println(x + “哈哈”)
		/**
     * 有1个参数,无返回值
     * x : 参数 1
     */
    @Test
    public void test2() {
     
        //Consumer  { void accept(T t); }
        Consumer<String> consumer = (x) -> System.out.println(x); //格式1
        Consumer<String> consumer2 = x -> System.out.println(x + "哈哈"); //格式2

        consumer.accept("祖国万岁");
        consumer2.accept("天下第一");
    }

(3) 有多个参数,并且有多条Lambda体语句,且有返回值

  • (x,y) -> {
    System.out.println(x);
    return x + y;
    }
 /**
     * 有一个或者多个参数,并且有多条Lambda体语句,且有返回值
     * 必须用大括号,包裹Lambda体,并且有return语句.
     */
    @Test
    public void test3(){
     
        //Comparable  { public int compareTo(T o); }
        Comparable<Integer> com = (x) -> {
     
            System.out.println("哈哈");
            return Integer.compare(1,x);
        };

        int i = com.compareTo(0);
        System.out.println(i);
    }

(4) 有 1个或者多个参数,并且Lambda 体只有一条语句,无论是否有返回值

  • (x) -> Integer.compare(1,x);
/**
     * 有多个参数,并且只有条Lambda体语句,且有返回值
     * 可以省略大括号,省略return语句
     */
    @Test
    public void test4(){
     
        Comparable<Integer> com = (x) -> Integer.compare(1,x);

        int i = com.compareTo(0);
        System.out.println(i);
    }

总结:
左右遇一,括号省
左侧推断,类型省
能省就省.

解释:
1.左右遇一:一,表示的是1个参数,则省略小括号,或者是Lambda体中只有1条语句,则省略大括号和return关键字.
2.Lambda 的参数列表的参数类型可以不用写.因为JVM的编译器可以根据上下文推断出参数类型.

3.Java 8 中内置的核心4大函数式接口

java 8中内置了几大函数式接口,减少了我们自定义函数式接口的编写.内置的函数式接口主要分为以下4大类.

  • Consumer: 消费性接口
    void accept(T t);

接口:

@FunctionalInterface
public interface Consumer<T> {
     
   
    void accept(T t);
 
}

应用:

 @Test
    public void test2() {
     
        //Consumer  { void accept(T t); }
        Consumer<String> consumer = (x) -> System.out.println(x); //格式1
        Consumer<String> consumer2 = x -> System.out.println(x + "哈哈"); //格式2

        consumer.accept("祖国万岁");
        consumer2.accept("天下第一");
    }
  • Supplier: 供给型接口
    T get();
@FunctionalInterface
public interface Supplier<T> {
     

    T get();
}
  • Function: 函数式接口
    R apply(T t);
@FunctionalInterface
public interface Function<T, R> {
     
   
    R apply(T t);
 
 }
  • Predicate: 断言型接口
    Boolean test(T t);
@FunctionalInterface
public interface Predicate<T> {
     

    boolean test(T t);
}

4.方法引用和构造引用

方法引用: 若Lambda 体中的内容有方法已经实现了,我们可以使用"方法引用" (可以理解为方法引用是Lambda 表达式的另外一种表现形式)

(1) 方法引用

  • 对象 :: 实例方法名
    接口中的方法的参数和返回值必须和引用方法的参数和返回值相同
	 /**
     * 对象::实例方法名
     * 接口中的方法的参数和返回值必须和引用方法的参数和返回值相同
     */
    @Test
    public void test1(){
     
        //demo1 
        // void accept(T t);
        PrintStream stream = System.out;
        Consumer<String> con = (x) -> stream.println(x);
        con.accept("哈哈");
        //可以简写
        Consumer<String> con2 = System.out::println;
        con2.accept("我爱祖国!!");

        //demo2
        //T get();
        Employee employee = new Employee(12,"张三",14,888.0);
        Supplier<String> sup = () -> employee.getName();
        System.out.println(sup.get());
        //简化
        Supplier<String> sup2 = employee::getName;
        System.out.println(sup2.get());

    }
  • 类 :: 静态方法名
    接口中的方法的参数和返回值必须和引用方法的参数和返回值相同
	/**
     * 类::静态方法名
     * 接口中的方法的参数和返回值必须和引用方法的参数和返回值相同
     */
    @Test
    public void test2(){
     
        //int compare(T o1, T o2);
        Comparator<Integer> com1 = (x,y) -> Integer.compare(x,y);
        //简化
        Comparator<Integer> com = Integer::compare;
    }
  • 类 :: 实例方法名
    参数列表中的第一蚕食是实例方法的调用者,第二个参数是实例方法的参数.则可以使用这种方式
	 /**
     * 类::实例方法名
     * 参数列表中的第一蚕食是实例方法的调用者,第二个参数是实例方法的参数.则可以使用这种方式
     */
    @Test
    public void test3(){
     
        // boolean test(T t, U u);
        BiPredicate<String,String> bi = (x,y) -> x.equals(y);
        System.out.println(bi.test("a","a"));
        //简化
        BiPredicate<String,String> bi2 = String::equals;
        System.out.println(bi2.test("a","ab"));

    }

(2) 构造器引用

格式:
类::new
函数式接口的参数需要和构造方法的参数一样,并且函数式接口的返回值和该类类型一致.

	/**
     * 构造器引用
     * 函数式接口的参数需要和构造方法的参数一样,并且函数式接口的返回值和该类类型一致.
     */
    @Test
    public void test4(){
     
        //demo1 无参的构造方法 public Employee() {}
        Supplier<Employee> sup = () -> new Employee();
        System.out.println(sup.get());
        //简化,构造器引用
        Supplier<Employee> sup2 = Employee::new;
        System.out.println(sup2.get());

        //demo2 一个参数的构造方法  public Employee(Integer id) {    this.id = id;   }
        Function<Integer,Employee> fun1 = (x) -> new Employee(x);
        System.out.println(fun1.apply(11));
        //构造器简化
        Function<Integer,Employee> fun2 = Employee::new;
        System.out.println(fun2.apply(22));
    }

(3) 数组引用
格式:
type[]::new

注意:
1.函数式接口的方法必须为两个参数,且第一个参数必须为integer类型,他代表数组的长度;第二个为数组类型,他代表数组的类型
2.type包括基本类型和引用类型

	/**
     * 数组引用
     * 函数式接口的方法必须为两个参数,且第一个参数必须为integer类型,他代表数组的长度;第二个为数组类型,他代表数组的类型
     */
    @Test
    public void test5(){
     
        Function<Integer,String[]> fun = (x) -> new String[x];
        System.out.println(fun.apply(3).length);
        //数组引用简化 ,第一个参数必须为integer类型,因为这个是数组的长度
        Function<Integer,String[]> fun2 = String[]::new;
        System.out.println(fun2.apply(4).length);

    }

5.实际操作

demo1
(1) 自定义函数式接口

/**
 * @author gl
 * @time 2020-07-10 0:21
 * @function : 函数式接口,只有一个抽象方法的接口
 * @step :
 */
@FunctionalInterface //这个修饰的接口就是函数式接口
public interface MyInterface {
     

    Integer getValue(Integer number);
}

(2) 自定义方法

 /**
     *  这个就是使用的策略模式
     * @param num 参数
     * @param myInterface 这是定义了一个计算的策略接口的参数,具体什么策略,自己实现
     */
    public Integer calculate(Integer num,MyInterface myInterface){
     
        return myInterface.getValue(num);
    }

(3) 业务中自己使用不同的策略

/**
     * 使用策略模式,外加Lambda表达式
     */
    @Test
    public void test6(){
     
        Integer value = calculate(2, x -> 2 * x);
        System.out.println(value);

        System.out.println(calculate(3,x -> x * x));

    }

总结

  • 1.因为我们现在基本是面向接口编程,所以Lambda表达式设计时为了简化我们接口编程的,所以Lambda表达式的左边一定是接口.
  • 2.又因为Lambda表达式只能实现一个方法,所以要求接口只能由一个抽象方法,这种接口为函数式接口.
  • 3.为了实现这个抽象接口,我们有几种实现方式,一种是自己实现,一种是引用别人实现好的.

你可能感兴趣的:(java,8新特性,javase)