新特性

1. JDK5

1.1. 增强for循环(For-Each)

没有下标,适合打印输出。

 for(int array : arrays){
 }

1.2. 可变参数

在方法声明中,在指定参数类型后加一个省略号...

一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。

可变参数的本质其实是数组

可变参数可匹配0个至多个参数

public void test(int a, int b, int ... i){
     // 此方法至少需要两个参数分别给a,b i可匹配0个至多个参数
}

1.3. 自动装箱拆箱

自动装箱的过程实际上是调用了valueOf()方法。

int age = 30;

// 自动装箱
Integer integer = age;

// 自动拆箱
int age2 = integer;

1.4. 泛型

  • Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
  • 常见形式有泛型类、泛型接口、泛型方法。
  • 语法:
    • <T,…> T称为类型占位符,表示一种引用类型。
  • 好处:
    • 提高代码的重用性。
    • 防止类型转换异常,提高代码的安全性。

2. JDK7

2.1. 数字之间可以用下划线分割。

int money = 100_000_000;
System.out.println(money); //100000000

2.2. switch支持String类型判断。

switch ("123"):
// ...

2.3. 实例化泛型类时,前面指定了泛型,后面可以省略,不再指定。

class MyGeneric<T> {
  // ...
}

MyGeneric<String> myGeneric = new MyGeneric<String>();
// 以上是JDK1.5的写法

// 在JDK1.7后,上述可写成
MyGeneric<String> myGeneric = new MyGeneric<>();

3. JDK8

3.1. 函数式接口

Functional Interface(函数式接口)定义:

  • 任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口。

    @FunctionalInterface
    public interface Runnable {
      public abstract void run();
    }
    
  • 对于函数式接口,可以通过lambda表达式来创建该接口的对象。

四大函数式接口

Function 函数型接口
image-20210826201652675
Image
package com.gs.function;

import java.util.function.Function;

/**
 * Function 函数型接口
 * <p>
 * 有一个输入参数,有一个输出
 * 只要是函数型接口 可以用Lambda表达式简化
 *
 * @author admin
 * @date 2021/8/26 8:14 下午
 */
public class Demo01 {
    public static void main(String[] args) {
        // 工具类:输出输入的值
//        Function<String, String> function = new Function<String, String>() {
//
//            @Override
//            public String apply(String s) {
//                return s;
//            }
//        };

        // 上述代码可改写成
//        Function function = (s) -> {
//            return s;
//        };

        // 代码只有return语句的话,return也可以省略
        Function function = s -> s;
        System.out.println(function.apply("!23"));

    }
}
Predicate 断定型接口
image-20210826202806302
Image
package com.gs.function;

import com.sun.org.apache.bcel.internal.generic.NEW;

import java.util.function.Predicate;

/**
 * 断定型接口,有个输入参数,返回值只能是布尔值。
 * @author admin
 * @date 2021/8/26 8:25 下午
 */
public class Demo02 {
    public static void main(String[] args) {
        // 判断字符串是否为空
//        Predicate<String> predicate = new Predicate<String>() {
//            @Override
//            public boolean test(String s) {
//                return s.isEmpty();
//            }
//        };

        Predicate<String> predicate = s -> s.isEmpty();

        System.out.println(predicate.test("123"));
    }
}
Consumer 消费型接口
image-20210826203525486
Image
package com.gs.function;

import java.util.function.Consumer;

/**
 * Consumer 消费型接口
 * 只有输入,没有返回值
 *
 * @author admin
 * @date 2021/8/26 8:34 下午
 */
public class Demo03 {
    public static void main(String[] args) {
        // 打印字符串
//        Consumer<String> consumer = new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//            }
//        };

        Consumer<String> consumer = s -> System.out.println(s);

        consumer.accept("123");
    }
}
Supplier 供给型接口
image-20210826203918386
Image
package com.gs.function;

import jdk.nashorn.internal.ir.ReturnNode;

import java.util.function.Supplier;

/**
 * Supplier 供给型接口
 * 没有参数,只有返回值
 * 
 * @author admin
 * @date 2021/8/26 8:38 下午
 */
public class Demo04 {
    public static void main(String[] args) {
//        Supplier<Integer> supplier = new Supplier<Integer>() {
//            @Override
//            public Integer get() {
//                return 1024;
//            }
//        };

        Supplier<Integer> supplier = () -> 1024;

        System.out.println(supplier.get());
    }
}

3.2. Lambda 表达式

  1. 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
  2. 使用 Lambda 表达式可以使代码变的更加简洁紧凑,避免匿名内部类定义过多,只留下核心的逻辑。

lambda 表达式的语法格式如下:

(parameters) -> expression 
  或 
(parameters) ->{ statements; }

以下是lambda表达式的重要特征:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

如:

// 1. 不需要参数,返回值为 5  
() -> 5  

// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  

// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  

// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  

// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)

以下二者效果等同:

new Thread(new Runnable() {
  @Override
  public void run() {
    System.out.println("hello1");
  }
}).start();

new Thread(() -> System.out.println("hello2")).start();

简化过程

简化过程:外部类->静态内部类->局部内部类->匿名内部类->lambda

public class TestLambda {

    // 3.静态内部类
    static class Like2 implements ILike{
        @Override
        public void lambda(){
            System.out.println("I like lambda2");
        }
    }

    public static void main(String[] args) {

        // 调用外部类创建对象
        ILike like1 = new Like();
        like1.lambda();

        // 调用静态内部类创建对象
        ILike like2 = new Like2();
        like2.lambda();


        // 4.局部内部类
        class Like3 implements ILike{
            @Override
            public void lambda(){
                System.out.println("I like lambda3");
            }
        }
        ILike like3 = new Like3();
        like3.lambda();

        // 5.匿名内部类,没有类名字,必须借助接口或者父类
        ILike like4 = new ILike() {
            @Override
            public void lambda() {
                System.out.println("I like lambda4");
            }
        };
        like4.lambda();

        // 6.用lambda简化
        ILike like5 = ()->{
            System.out.println("I like lambda5");
        };
        like5.lambda();
    }
}

// 1.定义一个函数接口
interface ILike{
    void lambda();
}

// 2.实现外部类
class Likx

注意

  1. lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
  2. 可以直接在 lambda 表达式中访问外层的局部变量
  3. 局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)
  4. 在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量

3.3. Stream流式计算

什么是流式计算?

大数据:存储 + 计算

集合、MySQL本质是存储东西的

计算都应该交给流来操作。

package com.gs.stream;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

/**
 * 题目要求:一分钟内完成此题,只能用一行代码实现
 * 现有5个用户,筛选:
 * 1. ID必须是偶数
 * 2. 年龄必须大于23岁
 * 3. 用户名转为大写字母
 * 4. 用户名字母倒着排序
 * 5. 只输出一个用户
 *
 * @author admin
 * @date 2021/8/26 8:49 下午
 */
public class Test {
    public static void main(String[] args) {

        User u1 = new User(1, "a", 21);
        User u2 = new User(2, "b", 22);
        User u3 = new User(3, "c", 23);
        User u4 = new User(4, "d", 24);
        User u5 = new User(6, "e", 25);

        // 集合就是存储
        List<User> list = Arrays.asList(u1, u2, u3, u4, u5);

        // 计算交给Stream流
        // lambda表达式、链式编程、函数式接口、Stream流式计算
        list.stream().filter(user -> user.getId() % 2 == 0)
                .filter(user -> user.getAge() > 23)
                .map(user -> user.getName().toUpperCase())
                .sorted(Comparator.reverseOrder())
                .limit(1)
                .forEach(System.out::println);


    }
}
List<String> list = users.stream().map(User::getName).collect(Collectors.toList());

3.4. 隐藏final

局部内部类访问外部类当前方法中的局部变量时不需要再添加final关键字

class Outer{
  public void method(){
    // 在此处定义的变量为局部变量
    String address = "gd";
    class Inner {
      // 如若在此处调用address,则局部变量需为常量,JDK1.8后可以不加final关键字
    }
    }
}

3.5. Optional类判空

解决java.lang.NullPointerException空指针异常的简单化。

JDK7前判空实现

User user = usersMapper.selectUserById(userId);
String userName = user.getUserName();
if(user!= null){
  if(userName != null && !userName.isEmpty()){
    .....
  }
}

JDK8开始

User user = usersMapper.selectUserById(userId);
Optional.ofNullable(user)
  .map(User::getUserName)
  .ifPresent(userName->{
    ....
  }
  • ofNullable 方法 :将指定值用Optional封装之后返回,如果该值为null,则返回一个空的Optional对象
  • empty 方法 :返回一个空的Optional实例
  • filter 方法 :如果值存在并且满足提供的谓词,就返回包含该值的Optional对象;否则返回一个空的 Optional对象
  • flatMap 方法 :如果值存在,就对该值执行提供的mapping函数调用,返回一个Optional类型的值,否则就返 回一个空的Optional对象
  • get 方法 :如果该值存在,将该值用Optional封装返回,否则抛出一个NoSuchElementException异常
  • ifPresent 方法 :如果值存在,就执行使用该值的方法调用,否则什么也不做
  • isPresent 方法 :如果值存在就返回true,否则返回false
  • map 方法 :如果值存在,就对该值执行提供的mapping函数调用
  • of 方法 :将指定值用Optional封装之后返回,如果该值为null,则抛出一个NullPointerException异常
  • orElse 方法:如果有值则将其返回,否则返回一个默认值
  • orElseGet 方法 :如果有值则将其返回,否则返回一个由指定的Supplier接口生成的值
  • orElseThrow 方法 :如果有值则将其返回,否则抛出一个由指定的Supplier接口生成的异常

3.6. 哈希表新增红黑树

JDK1.8+: 哈希表 = 数组 + 链表 + 红黑树。

4. JDK14

4.1. Instanceof模式匹配

新版判断后面可以做其他的事情,如跟上实例名和增加更多的判断。

// B extends A
// 判断B是否是A的子类

// 旧版的判断方法
if(B instanceof A){
  // ...
}

// 新版的判断,其中a在B instanceof A结果为true后相当于直接进行类型转换,后面可以带一些判断
if(B isntanceof A a){
  // ...
}
if(B isntanceof A a && a.getId() > 10){
  // ...
}

5. 版本对照

  1. Has been compiled by a more recent version of the Java Runtime (class file version 57.0)

    解决:切换JDK版本到指定的版本。

    对应版本表

    49 = Java 5
    50 = Java 6
    51 = Java 7
    52 = Java 8
    53 = Java 9
    54 = Java 10
    55 = Java 11
    56 = Java 12
    57 = Java 13
    58 = Java 14
    59 = Java 15
    60 = Java 16
    61 = Java 17
    62 = Java 18
    63 = Java 19
    
Copyright © rootwhois.cn 2021-2022 all right reserved,powered by GitbookFile Modify: 2023-03-05 10:55:52

results matching ""

    No results matching ""