Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java14 都来了,你还不会用 Java8吗?

Java14 都来了,你还不会用 Java8吗?

作者头像
代码宇宙
发布于 2023-02-23 02:13:26
发布于 2023-02-23 02:13:26
35300
代码可运行
举报
文章被收录于专栏:代码宇宙代码宇宙
运行总次数:0
代码可运行

前言

Java 8 于2014年3月18日发布,并且成为主流的 Java,如今,虽然 Java 14 都已经发布了,但是 开发者和公司选择的版本依旧是经久不衰的 Java 8 版本,如果你还不了解这些新特性,是时候学习一下了。

Java 8 更新的一些重要功能一览

  • Iterable 接口中的 forEach() 方法
  • 接口中的默认方法和静态方法
  • 功能接口和 Lambda 表达式
  • 用于集合上批量数据操作的 Java Stream API
  • Java 时间 API
  • 集合 API 的改进
  • 并发 API 改进
  • Java IO改进
  • 其他核心 API 改进

下面来简要了解一下这些Java 8功能。我将提供一些代码片段以更好地理解,因此,如果要在Java 8中运行程序,则必须按照以下步骤设置Java 8环境。

下载并安装JDK8。像其他Java版本一样,安装也很简单,运行下面的示例,必须要安装 JDK 环境。

下载最新的 IDEA 开发环境,这里我不推荐使用 Eclipse ,但是如果你有使用 Eclipse 习惯,那我在这里推荐你可以尝试 IDEA,因为它真的太棒啦~

Iterable 接口中的 forEach()方法

在 Java 8 以前,每当需要遍历 Collection 时,就需要创建一个 Iterator 来进行迭代 Collection 对象,然后针对 Collection 中 的每个元素将业务逻辑循环在一起。如果迭代器使用不正确,可能会抛出 ConcurrentModificationException。

Java 8 在接口中引入了forEach方法,java.lang.Iterable因此在编写代码时,我们仅关注业务逻辑。forEach方法将java.util.function.Consumer对象作为参数,因此有助于将我们的业务逻辑放在一个可以重用的单独位置。让我们通过简单的示例查看forEach用法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.journaldev.java8.foreach;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
import java.lang.Integer;

public class Java8ForEachExample {

    public static void main(String[] args) {

        //creating sample Collection
        List<Integer> myList = new ArrayList<Integer>();
        for(int i=0; i<10; i++) myList.add(i);

        //traversing using Iterator
        Iterator<Integer> it = myList.iterator();
        while(it.hasNext()){
            Integer i = it.next();
            System.out.println("Iterator Value::"+i);
        }

        //traversing through forEach method of Iterable with anonymous class
        myList.forEach(new Consumer<Integer>() {

            public void accept(Integer t) {
                System.out.println("forEach anonymous class Value::"+t);
            }

        });

        //traversing with Consumer interface implementation
        MyConsumer action = new MyConsumer();
        myList.forEach(action);

    }

}

//Consumer implementation that can be reused
class MyConsumer implements Consumer<Integer>{

    public void accept(Integer t) {
        System.out.println("Consumer impl Value::"+t);
    }


}

代码的行数可能会增加,但是forEach方法有助于将迭代逻辑和业务逻辑放在不同的位置,从而使关注点和代码更清晰地分离。

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

如果仔细阅读forEach方法的详细信息,会注意到它是在Iterable接口中定义的,但我们知道接口不能具有方法主体。从Java 8开始,接口已增强为具有实现的方法。我们可以使用default和static关键字来创建带有方法实现的接口。Iterable接口中的forEach方法实现为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}

我们知道Java不会在Class中提供多重继承,因为它会导致Diamond问题。由于接口现在类似于抽象类,因此现在如何使用接口处理它。解决方案是在这种情况下编译器将引发异常,我们将不得不在实现接口的类中提供实现逻辑。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.journaldev.java8.defaultmethod;

@FunctionalInterface
public interface Interface1 {

    void method1(String str);

    default void log(String str){
        System.out.println("I1 logging::"+str);
    }

    static void print(String str){
        System.out.println("Printing "+str);
    }

    //trying to override Object method gives compile-time error as
    //"A default method cannot override a method from java.lang.Object"

//    default String toString(){
//        return "i1";
//    }

}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.journaldev.java8.defaultmethod;

@FunctionalInterface
public interface Interface2 {

    void method2();

    default void log(String str){
        System.out.println("I2 logging::"+str);
    }

}

注意,两个接口都有一个带有实现逻辑的通用方法log()。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.journaldev.java8.defaultmethod;

public class MyClass implements Interface1, Interface2 {

    @Override
    public void method2() {
    }

    @Override
    public void method1(String str) {
    }

    //MyClass won't compile without having it's own log() implementation
    @Override
    public void log(String str){
        System.out.println("MyClass logging::"+str);
        Interface1.print("abc");
    }

}

如你所见, Interface1 具有在 MyClass.log() 方法实现中使用的静态方法实现。Java 8 在 Collection API 中大量使用默认和静态方法,并且添加了默认方法,以便使 JDK 8 之前的代码保持向后兼容。

如果层次结构中的任何类都具有具有相同的方法,则默认方法将变得无关紧要。由于任何实现接口的类都已经具有 Object 作为超类,因此如果接口中具有 equals(),hashCode() 默认方法,它将变得无关紧要。这就是为什么为了更清楚起见,不允许接口具有Object默认方法。

有关Java 8接口特性的完整详细信息,请阅读 Java 8接口更改。

功能接口和Lambda表达式

如果你注意到上述接口代码,则会注意到 @FunctionalInterface 注解。该功能接口是Java 8 中引入的新概念。具有一种抽象方法的接口就变成了功能接口。我们不需要使用 @FunctionalInterface 注解将接口标记为Functional Interface。@FunctionalInterface 注解是一种避免在功能接口中意外添加抽象方法的工具。您可以将其视为 @Override 批注,并且是使用它的最佳实践。java.lang.Runnable 使用单个抽象方法 run() 是功能接口的一个很好的例子。

功能接口的主要优点之一是可以使用 lambda 表达式实例化它们。在 Java 8 之前,可以用匿名类实例化一个接口,但是代码看起来很庞大。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Runnable r = new Runnable(){
    @Override
    public void run() {
            System.out.println("My Runnable");
    }};

由于功能接口只有一种方法,因此 lambda 表达式可以轻松提供该方法的实现。只需要提供方法参数和业务逻辑。例如,可以使用 lambda 表达式编写上面的实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Runnable r1 = () -> {
            System.out.println("My Runnable");
        };

如果方法实现中只有一条语句,那么我们也不需要大括号。例如,上面的Interface1匿名类可以使用lambda实例化,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Interface1 i1 = (s) -> System.out.println(s);

i1.method1("abc");

因此,lambda 表达式是轻松创建功能接口的匿名类的一种方法。使用 lambda 表达式对于代码运行没有任何的影响,因此要谨慎谨慎使用它,因为我们并不介意编写一些额外的代码行。

新包装 java.util.function 添加了带有功能接口束的,以提供 lambda 表达式和方法引用的目标类型。Lambda 表达式是一个非常复杂的话题,后续我会编写一篇文章专门针对 lambda 表达式。

您可以在 Java 8 Lambda Expressions Tutorial 中阅读完整的教程。

用于集合上批量数据操作的Java Stream API

java.util.stream 是Java 8中添加的一个新内容,以对该集合执行类似过滤/映射/遍历的操作。Stream API 将允许顺序执行和并行执行。这对我来说是非常好用的一个功能,因为我经常处理 Collections,而且通常使用很多的数据进行过滤数据,遍历数据,stream 就完美的解决了这个问题。

Collection 接口已使用 stream() 和 parallelStream() 默认方法进行了扩展,以获取用于顺序执行和并行执行的 Stream ,用一个简单的例子看看它们的用法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.journaldev.java8.stream;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class StreamExample {

    public static void main(String[] args) {

        List<Integer> myList = new ArrayList<>();
        for(int i=0; i<100; i++) myList.add(i);

        //sequential stream
        Stream<Integer> sequentialStream = myList.stream();

        //parallel stream
        Stream<Integer> parallelStream = myList.parallelStream();

        //using lambda with Stream API, filter example
        Stream<Integer> highNums = parallelStream.filter(p -> p > 90);
        //using lambda in forEach
        highNums.forEach(p -> System.out.println("High Nums parallel="+p));

        Stream<Integer> highNumsSeq = sequentialStream.filter(p -> p > 90);
        highNumsSeq.forEach(p -> System.out.println("High Nums sequential="+p));

    }

}

如果你运行示例代码,将获得如下输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
High Nums parallel=91
High Nums parallel=96
High Nums parallel=93
High Nums parallel=98
High Nums parallel=94
High Nums parallel=95
High Nums parallel=97
High Nums parallel=92
High Nums parallel=99
High Nums sequential=91
High Nums sequential=92
High Nums sequential=93
High Nums sequential=94
High Nums sequential=95
High Nums sequential=96
High Nums sequential=97
High Nums sequential=98
High Nums sequential=99

请注意,并行处理的时候。值不按顺序排列,因此在处理庞大的集合时,并行处理将非常有帮助。

这篇文章无法涵盖有关Stream API的所有内容,您可以在 Java 8 Stream API Example Tutorial 中阅读有关Stream API的所有内容。

Java 8 时间API

在之前的 Java 中使用日期,时间和时区一直很困难。Java 没有用于日期和时间的标准方法或 API。Java 8 有一个不错的附加功能是 java.time 软件包,它简化了 Java 中使用时间的过程。

仅查看 Java Time API 软件包,就可以感觉到它非常易于使用。它具有一些子包 java.time.format,这些子包提供用于打印和解析日期和时间的类,还有java.time.zone 提供对时区及其规则的支持。

新的 Time API 在整月的几个月和一周中的几天中都使用了枚举而不是整数常量。常用的类之一是 DateTimeFormatter 将 DateTime 对象转换为字符串。

有关完整的教程,请转到 Java日期时间API示例教程。

集合API的改进

在上面的介绍已经看到了 forEach() 方法和用于集合的 Stream API。

Collection API 中添加的一些新方法是:

IteratorforEachRemaining(Consumer action) 在所有元素都已处理完毕或该动作引发异常之前,对其余每个元素执行给定操作的默认方法。

CollectionremoveIf(Predicate filter) 删除此集合中所有满足给定谓词的元素的默认方法。

Collection spliterator() 该方法返回Spliterator实例,该实例可用于顺序或并行遍历元素。 地图replaceAll(),compute(),merge()方法。

另外还有一些具有 hash 冲突 的HashMap 类的性能改进

并发API改进

一些重要的并发API增强功能包括:

ConcurrentHashMap compute(),forEach(),forEachEntry(),forEachKey(),forEachValue(),merge(),reduce()和search()方法。

CompletableFuture 可以明确完成(设置其值和状态)。 Executors newWorkStealingPool() 使用所有可用处理器作为目标并行度级别创建窃取线程池的方法。

Java IO改进

我知道的一些IO改进:

Files.list(Path dir) 返回一个延迟加载的 Stream,其元素是目录中的文件夹和文件列表。

Files.lines(Path path) 返回一个读取指定文件所有行的文件流。

Files.find() 返回一个根据指定目录搜索指定文件的文件列表流。

BufferedReader.lines() 返回一个Stream,其元素是从此 BufferedReader 中读取的行。

其他核心API改进

一些杂项API改进在某些特殊情况可能会派上用场:

  • ThreadLocal 静态方法可以使用 withInitial 方法创建实例。
  • 比较器接口已扩展了许多默认和静态方法,用于自然排序,反向排序等。
  • Integer,Long 和 Double 包装器类中增加了 min(),max() 和 sum() 方法。
  • Boolean 类中的 logicalAnd() ,logicalOr() 和 logicalXor() 方法。
  • ZipFile.stream() 方法获取 ZIP 文件条目上的有序Stream,并以压缩时的顺序出现在 Stream 中。
  • Math 类中增加了几种实用方法。
  • jjs 添加命令以调用 Nashorn Engine。
  • jdeps 添加命令以分析类文件
  • JDBC-ODBC 连接桥已被删除。
  • PermGen 内存空间已被删除
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 代码宇宙 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Java学习笔记之二十八】深入了解Java8新特性
前言: Java 8 已经发布很久了,很多报道表明java 8 是一次重大的版本升级。在Java Code Geeks上已经有很多介绍Java 8新特性的文章,例如Playing with Java 8 – Lambdas and Concurrency、Java 8 Date Time API Tutorial : LocalDateTime和Abstract Class Versus Interface in the JDK 8 Era。本文还参考了一些其他资料,例如:15 Must Read Java
Angel_Kitty
2018/04/09
1.1K0
马上Java14要来了,你还不知道Java8的新特性?
Lambda表达式, 也可以称为闭包,它是Java8这个版本最重要的新特性.Lambda允许把函数作为一个方法的参数, 可以使代码变得更加简洁.
故里
2020/11/25
7240
马上Java14要来了,你还不知道Java8的新特性?
【Java_22】JDK 新特性
JDK 1.8 新特新 一、函数式接口 1. 函数式接口 ① 概念 * 有且仅有一个抽象方法的接口 ② 格式 @FunctionalInterface //使用该注解可以判断该接口是否是函数式接口。 public class 类名 { public abstract 返回值 方法名(参数列表); } 2. 函数式编程 ① Lambda 延迟 * Lambda 不使用不执行 ② 示例 //定义函数式接口 @Functiona
用户8250147
2021/02/04
4100
全网最通透的Java8版本特性讲解
以下是 Java 8 中的引入的部分新特性。关于 Java 8 新特性更详细的介绍可参考这里。
我没有三颗心脏
2020/08/20
9620
java8新特性(拉姆达表达式lambda)
形同点: 1.都是抽象类型; 2.都可以有实现方法(以前接口不行); 3.都可以不需要实现类或者继承者去实现所有方法,(以前不行,现在接口中默认方法不需要实现者实现)++ 不同点 ++1.抽象类不可以多重继承,接口可以(无论是多重类型继承还是多重行为继承); 2.抽象类和接口所反映出的设计理念不同。其实抽象类表示的是”is-a”关系,接口表示的是”like-a”关系; 3.接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值;抽象类中的变量默认是 default 型,其值可以在子类中重新定义,也可以重新赋值。++
全栈程序员站长
2022/11/05
4460
一次性实战java8 新特性(全)—— Lambda、Optional、stream、DateTime
本篇博客你将学到: 1.Lambda表达式 2.Optional类,告别空指针异常 3.Stream流式处理 4.时间处理LocalDate、LocalTime、LocalDateTime、ZonedDateTime、Clock、Duration 5.重复注解 6.扩展注释 7.更好的类型推荐机制 8.参数名字保存在字节码中 9.异步调用 CompletableFuture
源码之路
2020/09/03
2.6K0
Java8 新特性
Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以取代大部分的匿名内部类,可以写出更简洁、更灵活的代码。尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构。作为一种更紧凑的代码风格,使 Java 的语言表达能力得到提升。JDK 也提供了大量的内置函数式接口供我们使用,使得 Lambda 表达式的运用更加方便、高效。 【1】从匿名类到 Lambda 的转换:虽然使用 Lambda 表达式可以对某些接口进行简单的实现,但并不是所有的接口都可以使用 Lambda 表达式来实现。Lambda 规定接口中只能有一个需要被实现的方法,不是规定接口中只能有一个方法。
Java架构师必看
2021/05/14
9280
Java8 新特性
Java8特性接口的改变LambaStream时间API
函数式接口,该接口中只能由一个抽象方法,可以使用@FunctionalInterface注解修饰某个接口有且仅有一个抽象方法。
spilledyear
2018/10/09
4360
Java8 通关攻略
Java8 特别强大的是Lambda 表达式和Stream,通过它两新增和增强了很多包
乔戈里
2020/02/14
1.2K0
Java8 通关攻略
Java基础20:Java8新特性终极指南
毫无疑问,Java 8发行版是自Java 5(发行于2004,已经过了相当一段时间了)以来最具革命性的版本。Java 8 为Java语言、编译器、类库、开发工具与JVM(Java虚拟机)带来了大量新特性。在这篇教程中,我们将一一探索这些变化,并用真实的例子说明它们适用的场景。
程序员黄小斜
2019/04/07
5810
Java 函数式编程和 lambda 表达式
函数式编程更多时候是一种编程的思维方式,是种方法论。函数式与命令式编程的区别主要在于:函数式编程是告诉代码你要做什么,而命令式编程则是告诉代码要怎么做。说白了,函数式编程是基于某种语法或调用API去进行编程。例如,我们现在需要从一组数字中,找出最小的那个数字,若使用用命令式编程实现这个需求的话,那么所编写的代码如下:
芋道源码
2018/10/26
1K0
Java8新特性详解
Java 8 是oracle公司于2014年3月发布,可以看成是自Java 5 以来最具革命性的版本。Java 8为Java语言、编译器、类库、开发工具与JVM带来了大量新特性。
Jensen_97
2023/07/20
2.3K0
Java8新特性详解
Java8新增方法使用
Java8允许我们使用default关键字为接口添加非抽象的方法。这个特点也被称为扩展方法,下面是例子:
小森啦啦啦
2019/12/15
1.6K0
Java8 Lambda表达式.md什么是λ表达式λ表达式的类型λ表达式的使用其它相关概念
为了支持函数式编程,Java 8引入了Lambda表达式. 在Java 8中采用的是内部类来实现Lambda表达式.具体实现代码,可以通过debug看, 同时通过字节码查看工具及反编译工具来验证.
一个会写诗的程序员
2018/08/20
1.7K0
java8 函数式编程一
为什么要先从函数接口说起呢?因为我觉得这是 java8 函数式编程的入口呀!每个函数接口都带有 @FunctionalInterface 注释,有且仅有一个未实现的方法,表示接收 Lambda 表达式,它们存在的意义在于将代码块作为数据打包起来。
JMCui
2018/12/24
9730
Java 8教程
我们许多已经使用高级语言(如Scala)的人们并不知道Lambda表达式。在编程中,Lambda表达式(或函数)只是一个匿名函数,即一个没有名称而不被绑定到一个标识符的函数。它们被完全写在需要的地方,通常作为其他功能的参数。
IT小马哥
2020/03/18
1.8K0
java8新特性整理
官方文档:http://docs.oracle.com/javase/specs/jls/se8/html/index.html
pollyduan
2019/11/04
1.1K0
JAVA8十大新特性详解
Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法,示例如下:
用户3467126
2019/11/01
9560
java8 新特性
Java 8 Tutorial 接口的默认方法(Default Methods for Interfaces) Lambda表达式(Lambda expressions) 函数式接口(Functional Interfaces) 方法和构造函数引用(Method and Constructor References) Lamda 表达式作用域(Lambda Scopes) 访问局部变量 访问字段和静态变量 访问默认接口方法 内置函数式接口(Built-in Functional Inter
袁新栋-jeff.yuan
2020/08/26
5500
Java8新特性实践
Java 8 已经发行好几年了,作为一名Java程序员,再不应用它的美好的新特性肯定要被社会淘汰了。这篇文章,我作为一名Java8新手用代码实践Java8新特性,来探究它的美好。 1. Lambda表达式与Functional接口 Lambda表达式(也称为闭包),它允许把函数作为一个方法的参数(函数作为参数传递进方法中),或者把代码看成数据,这一特性和scala语言很像。 在最简单的形式中,一个lambda可以由用逗号分隔的参数列表、–>符号与函数体三部分表示。例如: Arrays.asList( "
神秘的寇先森
2018/05/30
9340
相关推荐
【Java学习笔记之二十八】深入了解Java8新特性
更多 >
LV.0
这个人很懒,什么都没有留下~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验