JDK8新特性

本文详细介绍了JDK8的新特性,重点讲解了Lambda表达式的组成、作用,如何使用Lambda表达式,以及函数式接口的概念和使用。同时,还讨论了接口的默认方法和静态方法的引入,以及方法引用的四种形式。最后提到了JDK8关于重复注解的改进。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JDK8新特性

一、Lambda表达式

1.组成:

  1. 以逗号隔开的参数列表(xx,xx,xx…)
  2. ->符号
  3. Lambda表达式方法体。(λ代码块)

2.lambda表达式的作用

1.删减了大量的无用代码,使得编程可以直奔核心;
2.让Java开始支持函数式编程。

2.1、lambda表达式删减了大量的无用代码,使得编程可以直奔核心。

  现在,先用传统方式,实现一个入门级的多线程程序,如下。

//以多线程为例。我们要启动一个多线程需要
    @Test
    void contextLoads() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程执行");
            }
        }).start();
    }

  程序中,new Thread()的参数是一个Runnable 接口,本次用匿名内部类方式实现了该接口,并重写了接口中的run()方法。但仔细读这种代码,容易发现 里面出现了大量的无用代码
在这里插入图片描述
代码中方法必不可少的东西:
(1)run()方法的参数列表:()
(2)方法体:System.out.print(…)
  其中很容易理解,对于一个方法(函数)而言,参数列表和方法体 是没法省略的。(有人可能问:为什么返回值类型可以省?因为lambda有自动类型推测机制,可以根据return值 自动推算出返回值类型)。
  好,搞懂以上后,lambda表达式的语法就出来了:
  lambda表达式由 参数列表 和方法体 两部分组成,并且二者之间使用“->”进行连接。lambda表达式的最大作用,就是对上述形式的“匿名内部类”进行简化。现在,将上述代码,使用lambda写成如下的等价程序。

 /**
 *Lambda表达式是用来简化代码的,所以对于方法中能省的全省掉,就是Lambda表达式
 *但有些是不能绝对省的1.方法体不能省 2.方法列表不能省
 */
 @Test
    void contextLoads() {
        new Thread( () ->{
                System.out.println("线程执行");
            }
        }).start();
    }

将原来那些冗余的代码去掉以后,我们的代码变得简洁了很多

2.2 、让Java开始支持函数式编程。

  再仔细观察这句代码:

 new Thread( () ->{
                System.out.println("线程执行");
            }
        }).start();

  在使用lambda时,我们可以将 一段“函数”传到一个方法中,本次是将“() ->System.out.println(“Hello World”)”这段函数 作为参数,传到了new Thread(…)的构造方法中了。大家回忆一下,在以前,方法的参数是不是只能是 变量或表达式?因此lambda的出现,就可以让函数传到了方法的参数中,这也称为函数式编程。

3.函数式接口

3.1、函数式接口的定义

  函数式接口是指被@FunctionalInterface注解修饰,且有且只有一个抽象方法的接口。这是因为假如接口有多个抽象方法,使用lambda表达式表达的就不知道是哪个方法了。

 @Test
    void contextLoads() {
        new Thread( () ->{
                System.out.println("线程执行");
            }
        }).start();
    }
//创建Thread对象时,需要传入一个Runnable对象,假如Runnable有多个抽象方法。lambda表达式就不知道重写哪个方法了

注意:lambda表达式重写的必须是函数式接口(或者只有一个抽象方法的抽象类)
函数式接口需要注意以下几点:

  • 即使没有标注@FunctionalInterface ,但是只有一个抽象方法,也称之为函数式接口。
  • 特殊情况:如果某个接口中有多个抽象方法,但是只有一个抽象方法是本接口新定义的,其他抽象方法和Object中已有的方法重复,那么该接口仍然是函数式接口。(这种情况比较极端,了解即可)
3.2、 jdk自带的函数式接口

存放位置:函数式接口大部分放在java.util.function包下
  jdk自带了4大函数式接口:

//四大核心函数式接口
//有参,无返回值(消费型)
@FunctionalInterface
public interface Consumer<T> {
    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
 }
 
//无参,有返回值(供给型)
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}
 
//有参,有返回值(函数型)
@FunctionalInterface
public interface Function<T, R> {
    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
    }

//断言式接口
 @FunctionalInterface
 public interface Predicate<T> {
    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
    }

4、Lambda表达式的用法

4.1、第一种用法:定义一个函数式接口,用Lambda重写抽象方法

基本语法:函数式接口 变量名= lambda表达式。
  上示例


@Test
   public void testLambda() {
       //1. 测试使用断言型接口
       Predicate<Integer> isGood = (sorce) -> {//la
           return sorce > 80;
       };
     //上面这一步就相当于我们重写了Predicate接口的test(T t)方法
       System.out.println("Predicate接口断言你成绩及格时间为"+isGood.test(100));
       isGood.test(100);//调用重写后的test方法
       
         //2. 测试使用函数型接口
       Function<Integer,String> function=(a)->{
           return "Function接口接收参数"+a+",并将它进行二次方计算返回"+a*a;
       };
       //使用lambda表达式重写Function接口的R apply(T t)方法
       System.out.println(function.apply(100));//调用重写后的apply方法
        //3. 测试使用消费型接口
       Consumer<String> consumer=(a)-> {System.out.println("Consumer接口消费了:"+a);};
       consumer.accept("苹果");
       // 4. 测试使用生产型接口
       Supplier<String> supplier=()->{
           return "Supplier生产粮食";
       };
       System.out.println(supplier.get());
   }
4.2、第二种用法:将Lambda表达式代表的函数式接口作为一个方法的参数存在

基本使用:下面的程序中我们用Lambda表达式( (word) -> word.toUpperCase(Locale.ROOT))代表Function接口作为参数传递给方法。

   @Test
    public void testLambda(){
        String s = toUpper("hello,world", (word) -> word.toUpperCase(Locale.ROOT));
        System.out.println(s);
    }
    public String toUpper(String word, Function<String,String> fun){
      //此时fun的抽象方法apply,已经被lambda重写了,所以下面调用的是重写后的apply方法。
        return fun.apply(word);
    }

二、接口的默认方法和静态方法

1、接口的默认方法

  在jdk8之前,接口只能写抽象方法,jdk8以后接口可以有自己默认的方法。该接口的实现类可以调用接口的默认方法。当然了实现类也可以重写接口的默认方法.

public interface MyInterface {
  default void say(String word){
      System.out.println("我说"+word);
   }
}


public class MyInterfaceImpl implements MyInterface {
}
   @Test
   public void testInterfaceDefaultMethod(){
       MyInterface myInterface=new MyInterfaceImpl();
       myInterface.say("hello world");
   }
2、接口的静态方法

  接口定义的静态方法,可以直接通过接口名.方法直接调用。

public interface MyInterface {
     static void staticMethod(String word){
         System.out.println("我说"+word);
    }
}
    @Test
    public void testInterfaceStaticMethod(){
        MyInterface.staticMethod("hello boy");
    }
}

三、方法引用

  jdk8允许使用::来引用一个已经存在的方法。其语法如下:
类名::方法名
注意:只需要写方法名,不需要写括号。
方法的引用,有以下4种
  1):引用静态方法 类名::方法
  2):引用某个对象实例的方法 实例名::方法
  3):引用某个类型任意对象的实例方法 类型(接口名)::方法
  4):引用构造方法 类名::new

四、重复注解

  java5引入注解以后,注解就被广泛使用,但是java5引入的注解有个局限,就是在同一个地方同一个注解只能使用一次。java8打破了这个限制,引入重复注解的概念。可以在同一个地方多次使用同一个注解。
  java8中使用@Repeatable定义重复注解。

/*@Repeatable 注解是用于声明其它类型注解的元注解,来表示这个声明的注解是  可重复的。
*@Repeatable的值是另一个注解,其可以通过这个另一个注解的值来包含这个可重复的注解。
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值