JDK1.8新特性及常用新特性

    技术2025-10-17  13

    JDK1.8的新特性

    *Lambda表达式

    新的日期API——Date time

    引入Optional——防止空指针异常

    *接口的默认方法和静态方法

    *新增方法引用格式

    *新增Stream类

    注解相关的改变

    支持并行(Parallel)数组

    对并发类(Concurrency)的扩展

    JavaFx

    1.接口的默认方法和静态方法

    在设计接口方法时使用default关键字,方法可以拥有方法体,所有子类默认实现(不用自己写,可以覆盖)接口的静态方法不会被实现类继承

    例:

    @FunctionalInterface public interface MyFunctionalInterface { /** * 有且仅有一个抽象方法 */ void method(); /** * 静态方法 */ static void get(){ } /** * 实现接口方法体 */ default void defaultMethod() { System.out.println("接口默认方法!"); } }
    @FunctionalInterface:在编译期起作用,编译期强制检查该接口是否符合函数式接口的条件,不符合就报错;即使不适用该注解,只要满足函数式接口的定义即函数式接口。

    2.函数式接口

    函数式思想:只关注做什么,不关注怎么做。

    有且仅有一个抽象方法的接口可以适用于Lambda使用的接口(只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导)

    格式:

    public interface 接口名称{ 返回值 方法名称(); }

    3.Lambda表达式(使用前提必须式函数式接口)

    1.语法

    三要素:参数、箭头、代码 即 (参数1,参数2…)->{}

    无参时使用括号(),有参数使用逗号分隔箭头是固定写法大括号相当于方法体

    2.Lambda省略规则

    参数类型可以省略,但是只能同时省略所有参数类型,否则都不要省略如果参数有且仅有一个,小括号可以省略如果大括号内的语句有且仅有一条,那么无论是否又返回值,return、大括号、分号都可以省略

    3.Lambda的延迟执行

    ​ 解决的问题:有些场景下的代码执行后结果不一定会被使用,造成性能浪费

    浪费案例 private void log(int level,String msg) { if(level == 1){ System.out.println(msg); } } @Test public void testStringConcat() { String str1 = "hhh"; String str2 = "csl"; String str3 = "csl123"; log(1,str1+str2+str3); }

    ​ 存在问题:无论level是否满足条件,log的第二个参数的那三个字符串一定会首先进行拼接并传入方法,然后才开始判断level。

    使用Lambda优化案例: private void log2(int level, MessageBuilder builder){ if (level == 1) { System.out.println(builder.builderMessage()); } } /** * 使用Lambda表达式实现字符串的拼接,并验证了延时执行 */ @Test public void testStringConcatLambda() { String str1 = "hhh"; String str2 = "csl"; String str3 = "csl123"; // Lambda方式进行延时执行 // 如果不符合要求,lambda将不会执行;即level=2时不会执行 log2(1, () -> str1+str2+str3); }

    4.使用Lambda作为参数和返回值

    ​ 如果方法的参数是一个函数式接口类型,那么就可以使用Lambda表达式进行替代。使用Lambda表达式作为方法参数,就是使用函数式接口作为方法参数。 例如 java.lang.Runnable接口就是一个函数式接口,假设有一个 startThread方法使用该接口作为参数,那么就可以使用Lambda进行传参。这种情况其实和Thread类的构造方法参数为Runnable没有本质区别。

    4.常用函数式接口

    函数型接口供给型接口消费型接口判断型接口

    1.函数型

    ​ 有参数,且需要返回值。

    @FunctionalInterface public interface Function<T, R> { /** *根据类型T的参数获取类型R的结果 */ R apply(T t); default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } /** *先进行操作再进行操作 */ default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } static <T> Function<T, T> identity() { return t -> t; } } public class FunctionTest { @Test public void testFunction(){ int num = parseInteger( Integer::parseInt, "10" ); System.out.println(num); } private Integer parseInteger(Function<String,Integer> function,String str){ return function.apply(str); } /** * 自定义函数模型拼接 */ @Test public void testAge(){ String str = "csl,16"; int ageNum = getAgeNum( s -> s.split(",")[1], Integer::parseInt, i -> i + 100, str ); System.out.println(ageNum); } /** * * @param one 将字符串截取数字年龄部分,得到字符串 * @param two 将上一步的字符串转换为int类型的数字 * @param three 将上一步的int数字累加100得到的结果 * @param str 处理的字符串 * @return 返回处理结果 */ private int getAgeNum(Function<String,String> one,Function<String,Integer> two,Function<Integer,Integer> three,String str) { return one.andThen(two).andThen(three).apply(str); } }

    2.供给型

    ​ 无参数,指定返回值类型,经常用于只关注过程的代码。

    @FunctionalInterface public interface Supplier<T> { /** * 用来获取一个泛型参数指定类型的对象数据,即对外提供 */ T get(); } public class SupplierTest { @Test public void testSupplier() { User user = getUser(User::new); System.out.println(user); } private User getUser(Supplier<User> supplier){ return supplier.get(); } /** * 获取最小值 */ @Test public void testMin() { int[] arr = {12,54,65,43,76,98,9}; int minNum = getMin(() -> { int min = arr[0]; for (int item : arr ) { if (item < min) { min = item; } } return min; }); System.out.println(minNum); } private int getMin(Supplier<Integer> supplier){ return supplier.get(); } }

    3.消费型

    ​ 不需要返回值,有参数,经常用于迭代。

    @FunctionalInterface public interface Consumer<T> { /** *消费一个指定泛型的数据 */ void accept(T t); /** *参数和返回值都是Consumer类型;首先做一个操作再做一个操作 */ default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } } public class ConsumerTest { /** * 单个参数 */ @Test public void testConSummerTest(){ User user = new User(); setUserDefaultSex(u -> u.setSex("男"),user); System.out.println(user); } private void setUserDefaultSex(Consumer<User> conSummer,User user) { conSummer.accept(user); } /** * 一个参数 */ @Test public void testConSummerTest2(){ User user = new User(); setUserDefaultNameAndSex(u -> u.setSex("男"),u->u.setName("张三"),user); System.out.println(user); } private void setUserDefaultNameAndSex(Consumer<User> one,Consumer<User> two,User user) { one.andThen(two).accept(user); } /** * 多个参数 */ @Test public void testConSummerTest3(){ User user = new User(); setUserDefault(u -> u.setSex("男"),u->u.setName("张三"),u->u.setId(1),user); System.out.println(user); } private void setUserDefault(Consumer<User> one,Consumer<User> two,Consumer<User> three,User user) { one.andThen(two).andThen(three).accept(user); } }

    4.判断型

    ​ 返回true/false,经常用于判断。

    @FunctionalInterface public interface Predicate<T> { /** *用于条件判断的场景 */ boolean test(T t); /** *与 */ default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } /** *取反 */ default Predicate<T> negate() { return (t) -> !test(t); } /** *或 */ default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } } public class PredicateTest { /** * 一个条件 */ @Test public void testPredicate() { strLongThan( s->s.length()>5,"实例" ); } private void strLongThan(Predicate<String> predicate,String str) { boolean flag = predicate.test(str); System.out.println("判断结果:"+flag); } /** * 两个条件 */ @Test public void testSuccess(){ successThan( s->s.contains("高"),s->s.contains("帅"),"高富" ); } private void successThan(Predicate<String> one,Predicate<String> two,String str) { boolean flag = one.and(two).test(str); System.out.println("强吗:"+flag); } /** * 集合筛选 */ @Test public void testFilter() { String[] array = {"迪丽热巴,女","马儿扎哈,男","地瓜嘎嘎,男","略略略,女"}; List<String> list = filter( s -> s.split(",")[0].length() == 4, s -> "男".equals(s.split(",")[1]), array ); System.out.println(list); } private List<String> filter(Predicate<String> one,Predicate<String> two,String[] arr){ List<String> list = new ArrayList<>(8); for (String s: arr ) { boolean flag = one.and(two).test(s); if (flag){ list.add(s); } } return list; } }

    5.方法引用

    方法引用符:::(双冒号)

    通过对象名引用成员方法;通过类名称引用静态方法;通过super引用成员方法;通过this引用成员方法。

    6.Stream流

    ​ 专注于做什么,而不是怎么做;解决集合中的常见问题。

    1.获取流

    List<String> list = new ArrayList<>(8); Set<String> set = new HashSet<>(8); Map<String,Object> map= new HashMap<String, Object>(8); String[] array = {"陈西瓜","张收到","呜哈哈","陈开心","王开心","张开心","样开心","李难过"};

    Collection接口实现类获取流

    // Collection接口的实现类获取流 Stream<String> streamList = list.stream(); Stream<String> streamSet = set.stream(); }

    Map接口实现类获取流

    // Map接口的实现类获取流 Stream<String> streamKey = map.keySet().stream(); Stream<Object> streamValue = map.values().stream();

    数组获取流

    // 数组获取流 Stream<String> streamArray = Stream.of(array);

    2.流的常用方法

    List<String> list = new ArrayList<>(8); list.add("陈西瓜"); list.add("张收到"); list.add("呜哈哈"); list.add("陈开心"); list.add("王开心"); list.add("张开心"); list.add("杨开心"); list.add("李难过"); 逐一处理:forEach list.stream().forEach(System.out::print); 过滤:filter list.stream().filter(e->e.contains("开心")); 映射:map(将stream里面的内容映射到另一个stream中) list.stream().map(e -> e.substring(2)); 统计个数:count list.stream().count(); 取用前n个:limit list.stream().limit(n); 跳到前n个:skip list.stream().skip(n); 通过skip+limit实现分页效果:skip+limit list.stream().skip(n).limit(n); 合并两个流:concat Stream.concat(one, two); 将流转换为集合:collect list.stream().collect(Collectors.toList());

    关于流的常用方法使用案例:

    @Test public void testCommonMethod() { List<String> list = new ArrayList<>(8); list.add("陈西瓜"); list.add("张收到"); list.add("呜哈哈"); list.add("陈开心"); list.add("王开心"); list.add("张开心"); list.add("杨开心"); list.add("李难过"); System.out.print("逐一处理:"); list.stream().forEach(System.out::print); System.out.print("\n过滤:"); list.stream().filter(e->e.contains("开心")).forEach(System.out::print); System.out.print("\n映射(将stream里面的内容映射到另一个stream中):"); list.stream().map(e -> e.substring(2)).forEach(System.out::print); System.out.print("\n统计个数. 即list.size(): "); System.out.print(list.stream().count()); System.out.print("\n取用前3个: "); list.stream().limit(3).forEach(System.out::print); System.out.print("\n跳到前1个:"); list.stream().skip(1).forEach(System.out::print); System.out.print("\n通过limit+skip可以实现分页效果:"); list.stream().skip(2).limit(2).forEach(System.out::print); System.out.print("\n合并两个流:"); Stream<String> one = list.stream().skip(0).limit(2); Stream<String> two = list.stream().skip(5).limit(2); Stream.concat(one, two).forEach(System.out::print); System.out.print("\n将流转为集合:"); List<String> collect = list.stream().collect(Collectors.toList()); collect.forEach(System.out::print); }
    Processed: 0.011, SQL: 9