JDK8新特性

总结:

1.写list的高效for循环时.可以list.for 有自动提示
2.写lambda表达式时 Collections.sort(list,(Person o1,Person o2)->{
return o1.getAge() - o2.getAge();
}); 时,鼠标在o2.getAge()后面.return 自动显示

3.数组也可以遍历 数组.for
4.:: 方法引用
5.stream流的reduce方法 .var ----->Integer reduce
6. 计算字符串a出现的次数 map和reduce组合
7.

一 Lambda表达式

创建一个空的maven项目
在这里插入图片描述

1.需求分析:

创建一个新的线程,指定线程要执行的任务

package cn.tedu.jdk.lambda;

public class Demo01Lambda {
   
    public static void main(String[] args) {
   
        //开启一个新的线程
        new Thread(new Runnable() {
   
            @Override
            public void run() {
   
                System.out.println("新线程中执行的代码:"+Thread.currentThread().getName());
            }
        }).start();
        System.out.println("主线程中的代码:"+Thread.currentThread().getName());
    }
}

代码分析:
1.Thread类需要一个Runnable接口作为参数.其中的run方法用来指定线程任务内容的核心
2.为了指定run方法,不得需要Runnable接口的实现类
3.为了省去定义一个Runnable实现类.,不得不使用匿名内部类
4.必须覆盖抽象run方法,方法名,方法参数,返回值类型,不得不重写一遍,而且不能出错
5.实际上,我们只关注方法体中的代码

2.Lambda表达式初体验

Lambda表达式是一个匿名函数,可以理解为是一段可以传递的代码,

new Thread(()->{
    System.out.println("新线程Lambda表达式..."+Thread.currentThread().getName()); })
			.start();

lambda表达式的优点:简化了匿名内部类的使用,语法更加简单
匿名内部类语法冗余,发现lambda表达式是简化匿名内部类的使用

3.Lambda语法规则

lambda省去了面向对象的条条框框,lambda语法规则有3部分组成

(参数类型 参数名称): 参数列表
{
   代码体}: 方法体
-> 箭头  分割参数列表和方法体 
lambda练习1

无参无返回值的lambda
定义一个接口,

package cn.tedu.jdk.lambda.service;

public interface UserService {
   
    void show(); //无参无返回值
}

然后创建主方法使用

package cn.tedu.jdk.lambda;

import cn.tedu.jdk.lambda.service.UserService;

public class Demo03Lambda {
   
    /**
     * (String[] args)->{}
     * @param args
     */
    public static void main(String[] args) {
   
        goShow(new UserService() {
   
            @Override
            public void show() {
   
                System.out.println("show 方法执行了...");
            }
        });
        System.out.println("-----------------");
        goShow(()->{
   
            System.out.println("lambda show方法 执行了...");
        });
    }
    public static void goShow(UserService userService){
   
        userService.show();
    }
}

输出:

show 方法执行了...
-----------------
lambda show方法 执行了...

lambda练习2

完成一个有参有返回值的lambda案例
创建一个Person对象

package cn.tedu.jdk.lambda.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
   
    private String name;
    private Integer age;
    private Integer height;
}

然后我们在main方法中,.List集合中保存多个person对象,然后对这些对象做根据age排序操作

package cn.tedu.jdk.lambda;

import cn.tedu.jdk.lambda.domain.Person;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Demo04Lambda {
   

    public static void main(String[] args) {
   
        List<Person> list = new ArrayList<Person>();
        list.add(new Person("周杰伦", 33, 175));
        list.add(new Person("刘德华", 50, 185));
        list.add(new Person("许攸", 46, 165));
        list.add(new Person("曹操", 30, 169));

//        Collections.sort(list, new Comparator<Person>() {
   
//            public int compare(Person o1, Person o2) {
   
//                return o1.getAge() - o2.getAge();
//            }
//        });
//        for (Person person : list) {
   
//            System.out.println(person);
//        }

        System.out.println("------------------");
        Collections.sort(list,(Person o1,Person o2)->{
   
            return o1.getAge() - o2.getAge();
        });
        for (Person person : list) {
   
            System.out.println(person);
        }
    }

}

我们发现在sort方法的第二个参数是一个Comparator接口的匿名内部类,且执行的方法有参数和返回值,我们可以改写为lambda表达式
输出结果

------------------
Person(name=曹操, age=30, height=169)
Person(name=周杰伦, age=33, height=175)
Person(name=许攸, age=46, height=165)
Person(name=刘德华, age=50, height=185)

4.@FunctionalInterface注解

使用lambda时,这个接口只能保证有一个抽象方法

package cn.tedu.jdk.lambda.service;

/**
 * @FunctionalInterface
 * 这是一个标志注解,被该注解修饰的接口,只能声明一个抽象方法
 */
@FunctionalInterface
public interface UserService {
   
    void show();
}

5.Lambda表达式的原理

在这里插入图片描述
lambda中的代码是在这个方法里面执行的
在lambda表达式编译的class文件中,cmd–>javap -c -p XXX.class指令
在这里插入图片描述

利用JDK自带工具javap 对字节码进行反汇编操作
javap -c -p XXX.class文件
-c 表示对代码进行反汇编
-p 显示所有的类和成员

在这个反编译的源码中我们看到了一个静态方法 lambda$main$0()

小结:

匿名内部类在反编译时.会产生一个class文件
lambda表达式在程序运行时会形成一个类
1.在类中会新增一个static方法,该方法体就是lambda表达式的代码
2.还会形成一个匿名内部类,实现接口,重写抽象方法
3.在接口中重写方法,调用新生成的方法

6.Lambda表达式省略写法

在lambda表达式标准写法基础上,可以省略的语法规则为:
1.小括号内的参数类型可以省略
2.如果小括号内有且仅有一个参数,则小括号可以省略
3.如果大括号内有且仅有一条语句,则可以同时省略大括号,return关键字及语句分号

package cn.tedu.jdk.lambda;

import cn.tedu.jdk.lambda.service.OrderService;
import cn.tedu.jdk.lambda.service.StudentService;

public class Demo05Lambda {
   
    public static void main(String[] args) {
   
        goStudent((String name, Integer age) -> {
   
            return name + age + "6666...";
        });
        //省略写法
        goStudent((name,age)->name + age + "6666...");
        System.out.println("--------------");

        goOrder((String name) -> {
   
            System.out.println("---->"+name);
            return 666;
        });
        //省略写法
        goOrder(name ->666);
    }

    public static void goStudent(StudentService studentService) {
   
        studentService.show("张三", 22);
    }

    public static void goOrder(OrderService orderService) {
   
        orderService.show("李四");
    }


}

7.Lambda表达式使用前提

lambda使用时有几个条件特别注意:
1.方法的参数或局部变量的类型必须为接口才能使用lambda
2.接口中有且仅有一个抽象方法 @FunctionalInterface

8.lambda和匿名内部类的对比

1.所需类型不同:
匿名内部类的类可以类,抽象类.接口,
lambda表达式需要的类型必须为接口
2.抽象方法的数量不一样
匿名内部类所需的接口中的抽象方法数量是随意的
lambda表达式所需的接口中只能有一个抽象方法
3.实现原理不一样
匿名内部类是在编译后生成的class
lambda表达式是在程序运行时动态生成class

二 接口中新增的方法

JDK8中针对接口有做新增,在JDK8之前

interface 接口名{
   
	静态常量;
	抽象方法;
}

在JDK8后,对接口做了增强,接口中可以有默认方法 和 静态方法

interface 接口名{
   
	静态常量;
	抽象方法;
	默认方法;
	静态方法;
}
默认方法
为什么要增加默认方法?

在JDK8以前,接口中只能有抽象方法和静态常量.会存在以下问题:
如果接口中新增抽象方法,那么实现类都必须抽象这个抽象方法.非常不利于接口的扩展

package cn.tedu.jdk.inter;

public interface Demo01Interface {
   
    public static void main(String[] args) {
   
        A b=new B();
        A c=new C();
    }
}
interface A{
   
    void test1();
    //接口中新增抽象方法,所有实现类都需要重写这个方法,不利于接口的扩展
    void test2();

}
class B implements A{
   
    @Override
    public void test1() {
   

    }

    @Override
    public void test2() {
   

    }
}
class C implements A{
   
    @Override
    public void test1() {
   

    }

    @Override
    public void test2() {
   

    }
}
接口中默认方法的格式?

接口中默认方法的语法格式

interface 接口名{
   
	修饰符 default 返回值类型 方法名(){
   方法体;}
}
package cn.tedu.jdk.inter;

public interface Demo01Interface {
   
    public static void main(String[] args) {
   
        A b=new B();
         b.test3();
        A c=new C();
    }
}
interface A{
   
    void test1();
    //接口中新增抽象方法,所有实现类都需要重写这个方法,不利于接口的扩展
    void test2();

    /**
     * 接口中定义的默认方法
     * @return
     */
    public default String test3(){
   
        System.out.println("接口中的默认方法执行了...");
        return "hello";
    }
}
class B implements A{
   
    @Override
    public void test1() {
   

    }

    @Override
    public void test2() {
   

    }

    @Override
    public String test3() {
   
        System.out.println("B 实现类重写了默认方法");
        return A.super.test3();
    }
}
class C implements A{
   
    @Override
    public void test1() {
   

    }

    @Override
    public void test2() {
   

    }
}
接口中默认方法的使用

接口中默认方法的使用有2种方式
1.实现类直接调用接口中的默认方法
2.实现类重写接口的默认方法

静态方法

JDK8中为接口新增了静态方法,作用也是为了接口的扩展
语法规则:

interface 接口名{
   
	修饰符 static 返回值类型 方法名(){
   
		方法体;
	}
}

代码:

package cn.tedu.jdk.inter;

public interface Demo01Interface {
   
    public static void main(String[] args) {
   
        A b = new B();
        b.test3();
        A c = new C();
        A.test4();
    }
}

interface A {
   
    void test1();

    //接口中新增抽象方法,所有实现类都需要重写这个方法,不利于接口的扩展
    void test2();

    /**
     * 接口中定义的默认方法
     *
     * @return
     */
    public default String test3() {
   
        System.out.println("接口中的默认方法执行了...");
        return "hello";
    }

    /**
     * 接口中的静态方法
     * @return
     */
    public static String test4() {
   
        System.out.println("接口中的静态方法...");
        return "hello";
    }
}

class B implements A {
   
    @Override
    public void test1() {
   

    }

    @Override
    public void test2() {
   

    }


//    @Override
//    public String test3() {
   
//        System.out.println("B 实现类重写了默认方法");
//        return A.super.test3();
//    }
}

class C implements A {
   
    @Override
    public void test1() {
   

    }

    @Override
    public void test2() {
   

    }
}
静态方法的使用

接口中的静态方法是不能被重写的,调用的话,只能通过接口类型来实现, 接口名.方法名

如果扩展的内容支持重写用默认方法default,否则用static
在这里插入图片描述

default和static的区别
  1. 默认方法通过实例调用,静态方法通过接口名调用
  2. 默认方法可以被继承,实现类可以直接调用接口默认方法,也可以重写接口默认方法
  3. 静态方法不能被继承,实现类不能重写接口中的静态方法,只能通过接口名调用

三 函数式接口

1.函数式接口的由来?

使用lambda表达式的前提是需要有函数式接口. 而使用lambda表达式不关心接口名,抽象方法名,
只关心抽象抽象方法的参数列表和返回值类型

package cn.tedu.jdk.fun;

public class Demo01Fun {
   

    public static void main(String[] args) {
   
        fun1(arr -> {
   
            int sum=0;
            for (int i : arr) {
   
                sum+=i;
            }
            return sum;
        });
    }

    public static void fun1(Operator operator) {
   
        int arr[]={
   1,2,3,4};
        int sum=operator.getSum(arr);
        System.out.println("sum="+sum);
    }
}

/**
 * 函数式接口
 */
@FunctionalInterface
interface Operator{
   
    int getSum(int[] arr);
}
2.函数式接口的由介绍

在JDK8后函数式接口.package java.util.function;包下,
Supplier接口, 无参有返回值方法 T get(); //发音 撒破裂
Consumer接口.有参无返回值的方法 void accept(T t);
Predicate接口, 有参有返回值的方法 boolean test(T t); //发音 破瑞dit

Supplier 接口

无参有返回值的接口,对于lambda表达式需要提供一个返回数据类型
Supplier 是用来生产数据的

@FunctionalInterface
public interface Supplier<T> {
   

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

代码:

package cn.tedu.jdk.fun;

import java.util.Arrays;
import java.util.function.Supplier;

/***
 * Supplier 函数式接口的使用
 */
public class SupplierTest {
   

    public static void main(String[] args) {
   
        fun1(()-> {
   
            int[] arr = {
   22, 66, 10, 5, 4, 77, 30};
            //计算出数组的最大值
            Arrays.sort(arr);
            return arr[arr.length - 1];
        });
    }
    private static void fun1(Supplier<Integer> supplier){
   
        //get()是一个无参有返回值的抽象方法
        Integer max = supplier.get();
        System.out.println("max="+max);
    }
}

Consumer接口

有参无返回值的接口,是用来消费数据的
Consumer,使用的时候需要指定一个泛型.来定义参数类型

@FunctionalInterface
public interface Consumer<T> {
   

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

使用: 将使用的数据统一转换为小写,输出

package cn.tedu.jdk;

import java.util.function.Consumer;

public class ConsumerTest {
   
    public static void main(String[] args) {
   
        fun2(msg -> {
   
            System.out.println(msg + "转换为小写:" + msg.toLowerCase());
        });
    }

    public static void fun2(Consumer<String> consumer) {
   
        consumer.accept("Hello World");
    }
}

默认方法:

    default Consumer<T> andThen(Consumer<? super T> after) {
   
        Objects.requireNonNull(after);
        return (T t) -> {
    accept(t); after.accept(t); };
    }
package cn.tedu

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值