本文介绍Java8 新特性。

一、接口支持默认方法(default)

Java8 允许接口里编写带具体实现的方法,使用default关键字修饰
优势:接口版本迭代时,不会破坏原有实现类代码,拓展性更强

// 定义学习行为接口
public interface Study {
    // 抽象方法,由实现类重写
    void learn();

    // 默认方法,自带实现逻辑
    default void play(String name) {
        System.out.println("我和" + name + "一起玩");
    }
}
// 接口实现类
public class Student implements Study {
    // 重写抽象学习方法
    @Override
    public void learn() {
        System.out.println("认真学习Java8");
    }
}
// 调用默认方法
new Student().play("小码哥");

二、Lambda 表达式

作用:简化冗余的匿名内部类写法,精简代码结构

传统匿名内部类写法

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

public class LambdaOldDemo {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("peter", "anna", "mike");
        // 字符串集合倒序排序
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String a, String b) {
                return b.compareTo(a);
            }
        });
    }
}

Lambda精简写法

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

public class LambdaNewDemo {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("peter", "anna", "mike");
        // lambda表达式实现排序逻辑
        Collections.sort(list, (a, b) -> b.compareTo(a));
    }
}

进一步简化写法

list.sort((a, b) -> b.compareTo(a));

三、函数式接口(@FunctionalInterface)

定义:仅包含一个抽象方法的接口,是Lambda表达式使用的前提
注解用于编译校验格式合法性

// 标记为函数式接口
@FunctionalInterface
public interface Converter<T, R> {
    // 通用类型转换抽象方法
    R convert(T from);
}
public class FuncInterfaceTest {
    public static void main(String[] args) {
        // lambda实现字符串转数字
        Converter<String, Integer> c = s -> Integer.valueOf(s);
        Integer num = c.convert("123");
        System.out.println(num); // 输出123
    }
}

四、方法引用(::)

基于Lambda再次精简,直接调用现有方法、构造方法

静态方法引用

// 引用Integer静态转换方法
Converter<String, Integer> c = Integer::valueOf;

实例方法引用

public class Demo {
    // 截取字符串首字符
    public String first(String s) {
        return s.charAt(0)+"";
    }

    public static void main(String[] args) {
        Demo d = new Demo();
        // 引用实例对象方法
        Converter<String, String> c = d::first;
        System.out.println(c.convert("Java")); // 输出J
    }
}

构造器引用

// 用户实体类
class User {
    String name;
    // 带参构造方法
    User(String name) {
        this.name = name;
    }
}

// 函数式工厂接口
@FunctionalInterface
interface UserFactory {
    User create(String name);
}

public class ConstructorRefTest {
    public static void main(String[] args) {
        // 引用构造器创建对象
        UserFactory f = User::new;
        User u = f.create("szxmg");
    }
}

五、Lambda 变量访问规则

  1. 局部变量默认隐式final修饰,不可二次赋值修改
public class LambdaVarTest {
    public static void main(String[] args) {
        int x = 1;
        // 使用外层局部变量运算
        Converter<Integer, String> c = i -> String.valueOf(i + x);
        // x = 2; 重新赋值会编译报错
    }
}
  1. 成员变量、静态变量支持读写操作
  2. Lambda内部无法直接访问接口默认方法

六、四大内置函数式接口(高频常用)

1. Predicate 断言判断接口,返回布尔结果

import java.util.function.Predicate;

public class PredicateDemo {
    public static void main(String[] args) {
        // 判断字符串长度是否大于3
        Predicate<String> p = s -> s.length() > 3;
        System.out.println(p.test("java")); // 输出true
    }
}

2. Function 类型转换接口,入参出参不同

import java.util.function.Function;

public class FunctionDemo {
    public static void main(String[] args) {
        // 获取字符串长度
        Function<String, Integer> f = s -> s.length();
        System.out.println(f.apply("szxmg")); // 输出5
    }
}

3. Consumer 消费接口,只处理数据无返回值

import java.util.function.Consumer;

public class ConsumerDemo {
    public static void main(String[] args) {
        // 打印拼接文本
        Consumer<String> con = s -> System.out.println("你好:"+s);
        con.accept("双栈小码哥");
    }
}

4. Supplier 供给接口,无入参只返回数据

import java.util.function.Supplier;
import java.util.Date;

public class SupplierDemo {
    public static void main(String[] args) {
        // 获取当前系统时间
        Supplier<Date> sup = Date::new;
        System.out.println(sup.get());
    }
}

七、Stream 流

简化集合操作,链式完成筛选、排序、转换、统计等功能

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class StreamDemo {
    public static void main(String[] args) {
        // 初始化测试集合数据
        List<String> list = Arrays.asList("ddd2", "aaa2", "bbb1", "aaa1", "bbb3", "ccc");

        // filter:过滤以a开头的元素
        list.stream()
            .filter(s -> s.startsWith("a"))
            .forEach(System.out::println);

        // sorted:自然排序
        list.stream().sorted().forEach(System.out::println);

        // map:字符统一转为大写
        list.stream()
            .map(String::toUpperCase)
            .forEach(System.out::println);

        // anyMatch:判断是否存在指定开头元素
        boolean hasA = list.stream().anyMatch(s -> s.startsWith("a"));

        // count:统计符合条件元素个数
        long cnt = list.stream().filter(s -> s.startsWith("b")).count();

        // reduce:拼接所有元素字符串
        Optional<String> res = list.stream().reduce((s1, s2) -> s1 + "-" + s2);
        res.ifPresent(System.out::println);

        // parallelStream:并行流,多线程加速处理
        list.parallelStream().forEach(System.out::println);
    }
}

八、Map集合新增实用方法

便捷实现不存在赋值、计算更新、合并数据等操作

import java.util.HashMap;
import java.util.Map;

public class MapNewFuncDemo {
    public static void main(String[] args) {
        Map<Integer, String> map = new HashMap<>();
        // 键不存在时才存入数据
        map.putIfAbsent(1, "Java");
        // 根据键动态计算赋值
        map.computeIfAbsent(2, k -> "Python");
        // 合并相同键的字符串内容
        map.merge(1, "8", String::concat);
    }
}

九、全新日期时间 API(java.time)

替代老旧线程不安全的Date、Calendar类,使用更简洁稳定

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class TimeApiDemo {
    public static void main(String[] args) {
        // 获取当前日期
        LocalDate today = LocalDate.now();
        // 获取当前时分秒
        LocalTime now = LocalTime.now();
        // 获取完整日期时间
        LocalDateTime dt = LocalDateTime.now();
        // 自定义时间格式化模板
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 格式化输出时间
        System.out.println(dt.format(fmt));
    }
}

十、重复注解(@Repeatable)

支持同一个位置多次添加相同类型注解

import java.lang.annotation.Repeatable;

// 容器注解
@interface Hints {
    Hint[] value();
}

// 可重复标记注解
@Repeatable(Hints.class)
@interface Hint {
    String value();
}

// 同一类上重复使用注解
@Hint("a")
@Hint("b")
class Demo {}

总结

Java8 核心知识点汇总:

  • 接口 default 默认方法
  • Lambda 表达式简化代码
  • 函数式接口规范定义
  • 方法引用进一步精简写法
  • Stream流高效处理集合
  • Map集合拓展操作方法
  • 线程安全的新日期API
  • 支持重复注解特性

更多推荐