Java8编程新思想速览

u=1933633967,2722140240&fm=15&gp=0.jpg

Java为什么还在变化?

Java从出生到现在已经有近30年的时间了,为什么它还需要不断的变化呢?首先Java也不是尽善尽美的,毕竟每种语言都只是在整个编程的生态系统中占据某个位置而已,此外硬件条件、程序的规模、数据的量级等等都是逐渐变化的。Java语言也需要去主动拥抱这些变化,综合起来可以把Java为什么还在变化的原因总结为一下三点:

  • 我们在之前的Java版本中要充分利用现代CPU多核心的优势,就需要编写多线程代码,而多线程代码不仅编写复杂还容易出错;
  • 函数式比命令式更适应新的体系架构;
    • 什么是函数式编程:函数式编程指的是使用这种方式编写的代码,它的语体是表达式形式的,主要是用来计算的表达式(不是编程语言中的Function/Method的概念)
    • 什么是命令式编程:命令式编程指的是使用这种方式编写的代码,它的语体是面向对象编程中常规的语句形式;
    • 为什么需要函数式编程:后面会细说
  • 相比其他语言,实现相同功能的代码量一直是Java被人诟病的地方;

Java8引入的核心思想

Java8作为自Java5以来变化最大的一个版本,它引入的核心思想主要就是为了把计算从面向对象的体系里独立出来。随着现在的业务逻辑越来越复杂,单纯面向对象的编程方式在处理频繁多变的计算类业务逻辑时,显得越来越笨拙。而一些函数式编程语言在这方面却大获成功,这给与了Java的设计者相当大的生存压力。面向对象思想的强大之处在于,它能很自然的对真实世界一个个实体的属性和行为进行抽象。而计算更多的是发生在对象之间,它像是一个没有固定形态的工具。所以把函数式编程思想引入到Java中来,作为面向对象思想的一个补充是很有必要的。

Java8中引入函数式编程思想的方式非常的巧妙,可以总结为一下两点:

  • 将方法和Lambda作为一等公民——像基本数据类型和对象引用一样的能在程序运行时传递;
  • 在没有可变共享状态时,函数或方法可以有效、安全地并行执行——通过流API在底层进行实现;

Java8带来了哪些新特性?

以下新特性部分先写个知识点的大纲,后续再分章节逐一细说。

Stream API

Streams是Java8的核心内容,另外的两项特性(方法引用/Lambda、接口默认函数)主要就是用来实现Streams(流处理);

为什么需要流?

  • 现有的对集合的处理代码,显得很繁琐(嵌套的循环、条件判断等);
  • 不能利用多核;

StreamAPI的设计思想

  • 让集合保留他存储和访问数据的功能,而使用Stream来对数据进行计算;

向方法中传递代码

Java语言中的一等公民

  • 编程语言的整个目的就在于操作值,在Java8之前,这个值包括基本数据类型和对象的引用;
  • 在Java中还有方法和类,在执行期间是不能被传递的,所以是二等公民;
  • Java 8中新增了函数——值的一种新形式;

在JavaScript中,类也是可以传递的。

Scala和Groovy等语言的实践已经证明,让方法等概念作为一等值可以扩充程序员的工具库,
从而让编程变得更容易。

方法引用的写法

Java8之前的写法

File[] files = new File(path).listFiles(new FileFilter() {
    @Override
    public boolean accept(File pathname) {
        return pathname.isHidden();
    }
});

Java8中的写法

File[] files = new File(path).listFiles(File::isHidden);

最大的好处是:我们的代码现在读起来更接近问题的陈述了。

匿名函数-Lambda

  • 除了允许(命名)函数成为一等值外,Java 8还体现了更广义的将函数作为值的思想,包括Lambda(匿名函数)。

  • 对于已有的方法,可以很方便的使用方法引用的写法,但是如果是一段即时代码(比如一个计算公式),直接用匿名函数的形式传入方法中,会更简洁。否则需要定义一个类、一个方法,把这个计算公式放到方法中。

    new File(path).listFiles(file -> file.isHidden());
    

    listFiles()方法中需要的参数是一个FileFilter,为什么可以传入一个Lambda表达式

接口中的默认方法

为什么要在接口中增加默认方法?

  • Java的设计者发现JDK中的接口也需要修改,但如果直接修改接口的话,意味着接口的实现者都需要跟着修改,这是毁灭性的灾难。所以设计了接口的默认方法,所有的实现类都可以使用这些默认接口,而不需要修改自身。

Optional

为了更好的解决和避免NPE异常,Java 8中引入了一个新的类java.util.Optional。

这是一个封装Optional值的类。

举例来说,使用新的类意味着,如果你知道一个人可能有也可能没有车,那么Person类内部的car变量就不应该声明为Car,遭遇某人没有车时把null引用赋值给它,而是将其声明为Optional类型。

变量存在时,Optional类只是对类简单封装。变量不存在时,缺失的值会被建模成一个“空”的Optional对象,由方法Optional.empty()返回。Optional.empty()方法是一个静态工厂方法,它返回Optional类的特定单一实例。

null引用和Optional.empty()有什么本质的区别吗?

使用Optional而不是null的一个非常重要而又实际的语义区别是,第一个例子中,我们在声明变量时使用的是Optional类型,而不是Car类型,这句声明非常清楚地表明了这里发生变量缺失是允许的。与此相反,使用Car这样的类型,可能将变量赋值为null,这意味着你需要独立面对这些,你只能依赖你对业务模型的理解,判断一个null是否属于该变量的有效范畴。

你可能感兴趣的:(Java8编程新思想速览)