暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

浅尝JAVA8新特性

源成蹊 2019-05-05
222

最近浏览Stack OverFlow寻求帮助时,发现国外一些coder已经在玩java12了。此时已是19年5月,去官网一览,发现j2ee 12上线已有些时日。其下载列表中,官网也只明列了:jdk12、11、8~

现在企业开发中,一般都是用的jdk8.其最主要原因是,低版本稳定啊。当然,很多小企业用的还是7、甚至老古董还在玩之前的版本(这位年轻人挺不客气啊)其实,我觉得还有更多原因是因为:

Oracle收购了Sun公司后,就像其收购了MySql一样,有闭源的风险。

之前一段时间很讨厌苹果公司,其App Store收取开发者30%的服务费,觉得它吃相难看,再后来,腾讯有了小程序和苹果对弈,苹果妥协。但腾讯要收取50%,此事不妥,后又改为流水超过50w再收,不超则免。哎,真的是,每个屠龙勇士屠完龙之后自己又变成了恶龙~不过也期望某天有人屠了Oracle吧

好了,正文开始~

java SE jdk8新特性如下:

1  默认方法
2 函数式接口
3 Lambda 表达式
4 方法引用
5 Stream
6 Optional 类
7 Nashorn, JavaScript 引擎
8 新的日期时间 API
9 Base64

这个顺序是小可特意排的,因为前6个都与Lambda、Stream有关,但学习得有先后之分,此处也只会浅析前6个特性。


1.默认方法

简单说,默认方法就是接口中可以有方法体,实现类可以选择不去实现该方法

语法:接口中,方法前+个default关键字,即可声明为默认方法

为什么要有这个特性?

接口的缺点:当需要修改接口时候,需要修改全部实现该接口的类。

目前jdk7及之前的集合框架没有forEach方法,通常能想到的解决方案是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法再给接口添加新方法的同时不影响已有的实现。所以引进了默认方法。他们的目的是为了解决接口的修改与现有的实现不兼容的问题

既然接口中能有方法体了,那么接口中也就可以有静态方法了。但是default不能与static一起使用奥~


2.函数式接口

很简单,函数式接口,定义就是接口中有且只有一个抽象方法。

你可能会说,接口中不就只能有抽象方法么,那不就是只有一个方法的接口?那是java7及以前了。现在接口中除了抽象方法,还可以有默认方法呀~

除了上文中的定义,函数式接口你还需要注意以下两点:

1>函数式接口可以定义Object定义过的任何公有方法。即Object的公有方法被视为函数式接口的隐式成员。因为函数式接口的实例会默认自动实现它们

2>默认方法和静态方法,不会违反函数式接口的约定

简单实例:

@FunctionalInterface   //该注解【可选】用以声明:该接口是一个函数式接口。作用:使用该注解后,该接口下只能有一个抽象方法,多了报错
public interface ITest{
     void say(String msg);
 }

jdk8中在java.util.function包下增加了一系列函数式通用接口,如:

Predicate<T>,Consumer<T>,Function<T,R>,Supplier<T>等等。给大家说这些是让它们混个眼熟。在使用Stream的Api中,你会发现,很多API的参数类型就是这些接口。它们实质上,就是官方定义了一些通用的方法。如Predicate<T>,该接口中有个:boolean test(T t)方法,可以返回个boolean值。当你需要个断言时,就可以使用这个Predicate官方接口来实现了


3.Lambda表达式

这是java语言自范型、注解后,发布的另一个重要的新特性了。

λ表达式语法:

1.(parameters) -> expression                  //表达式

2.或者 (parameters) ->{ statements;  }    //陈述句

语法特点:

1.可选类型声明:不需要声明参数类型即可

2.可选参数的圆括号:当有多个参数时才必需加上圆括号

3.可选的大括号:       如果主体中只有一条语句,就不需要大括号

4.可选的返回关键字:如果主体中只有一个表达式,则编译器自动返回值

优点:

1>允许把函数作为一个方法的参数(有丢丢像面向函数编程靠近了

2>使用λ表达式可以使代码更加简洁紧凑

使用场景:作为函数式接口的实现(当然,为承接上文,此处demo主要为此)

简单实例:

//定义一个函数式接口
interface ITest{
  void say(String msg);
}
public static void main(String[] args) {
   //java7可以使用匿名内部类来写这个接口的实现
ITest test1 = new ITest() {
@Override
public void say(String msg) {
System.out.println(">>>>>>>>>"+msg);
}
};
//java8使用Lambda
ITest test2 = (msg) -> System.out.println(msg);
}

缺点:

1.Lambda的语句中,不能抛出异常,需要手动处理

2.不能控制流程,比如在forEach方法中,λ表达式不能continue或break等

3.Lambda中变量不能更改,即可看做隐式常量

这么点缺点,丝毫不影响它的使用方便啊~


4.方法引用

双冒号操作符::

双冒号运算操作符是类方法的句柄,Lambda表达式的一种简写

语法如下:

类名::方法名

注意:

1.方法名后没有()

2.懒加载方法是否调用要看调用方使用情况

实例:

//java8使用Lambda
ITest test2 = (msg) -> System.out.println(msg);
//替换为如下:
ITest test2 =  System.out::println;


5.Stream

介绍:Stream(流)是一个来自数据源的元素队列并支持聚合操作。简单来说,就是对集合做操作的~

1.其内元素是特定类型对象<范型>,形成一个队列。Stream并不会存储元素,而是按需计算

2.数据源:流的来源可以是集合、数组、I/O channel等

3.聚合操作:类似SQL语句的操作。比如filter、map、sorted等

特征:

1.中间操作都会返回流对象本身。这样多个操作可以串连成一个管道

2.内部迭代:以前对集合遍历都是通过Iterator或者for-each方式,显式得在集合外部进行迭代叫外部迭代。Stream通过访问者模式提供了内部迭代的方式


集合对象生成流对象:

java.util.Collection接口中提供了两个默认方法:

1default Stream<E> stream(){...}         //串行流
2default Stream<E> parallelStream(){...} //并行流

实例:

//取出List<User>中,对象年龄是23的其记录id
List<Long> ids = list.stream().filter(n -> n.getAge() == 23).map( n -> n.getUid()).collect(Collectors.toList());

Steam流对象提供的API:forEach()、filter()、map()、sorted()等等。精力有限,诸多末节,不做细述。


6.Optional

这个特性挺没劲的,如果不是Stream流,我压根没打算用这个对象。

介绍:Optional类是jdk8中引入的一个可以为null的容器对象,其引入主要是为了避免我们太多精力去判断对象是否为null,解决空指针异常......(其实吧,使用了这个对象未必比我加一句判断省劲吧)所以,挺没趣的,记你这么多API徒然浪费我有限的脑存。了解下就好

其是个容器:它可以保存类型T的值,或者保存null。如果值存在则isPresent()方法会返回true,然后调用get()方法会返回该对象

在Stream流对象中,返回值为Optional常用的成员方法有:

Optional<T>  findFirst(); //拿到流对象[集合]中的第一条数据,放在Optional容器中
Optional<T> findAny();

实例:

//给新List的每条数据set对应值,若users集合中未找到数据,则设置null
list.forEachn -n.setUser(users.stream().filter(m -m.getAge()==23).findFirst().orElse(null)));

好了,以上是关于jdk8中比较重要的新特性了。主要是Lambda表达式与Stream流对象~

java也不再向以往一样总是古板不变了,面向对象与面向函数各有优劣。什么技术都不是一成不变,可以一统江湖的。语言也好,框架也罢,都是为了将所有现实的业务场景抽象得抽离出一套统一形式来,方便大家开发,提升效率~

接下来一段时间,可能没太多精力,以后抽空再来陆续总结所得吧


SEE U


文章转载自源成蹊,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论