java8特性

Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。

1.lambda表达式 & 函数式接口

详见lambda表达式总结

2. 方法引用

方法引用的规定,实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!至于返回值就不作要求

方法引用通过方法的名字来指向一个方法。方法引用可以使语言的构造更紧凑简洁,减少冗余代码。方法引用使用一对冒号 ::

引用对象的实例方法 Object::instanceMethodName
引用类的静态方法 ClassName::staticMethodName
引用类的实例方法 ClassName::methodName
引用构造方法 ClassName::new

1、2、4相对好理解,第三个在Java 8 In Action 是这样介绍的, 指向任意类型实例方法的方法引用(我觉得叫类的任意对象的实例方法引用更直观)

它要求接口方法的参数必须比引用方法的参数多一个。而且第一个参数要是该引用方法的所在类型的或其父类,除接口方法的第一个参数以外, 其余参数的类型要求一样。

example1,一个参数

  1. public  class Test1 {
  2.     public void a(){
  3.     }
  4.     public static void main(String[] args) {
  5.         MyInter m = Test1::a;
  6.     }
  7. }
  8. @FunctionalInterface
  9. interface MyInter {
  10.     //入参参数比Test1的a方法多一个,且Test1::a的Test1与该入参类型Test1相同
  11.     public void d(Test1 d);
  12. }

example2,两个参数

  1. public  class Test1 {
  2.     public void a(Integer param1,int param2){
  3.     }
  4.     public static void main(String[] args) {
  5.         MyInter m = Test1::a;
  6.     }
  7. }
  8. @FunctionalInterface
  9. interface MyInter {
  10.     //该接口参数比上述的a方法参数数量多一个,除去第一个,其它类型一致(可兼容,如可以一个int,一个Integer)
  11.     //且Test1::a的Test1是该入参类型Test1相同
  12.     public void d(Test1 d,int param1,int param2);
  13. }

example3 继承(参考上转型)

  1. public  class Test1 {
  2.     public void a(Integer param1,int param2){
  3.     }
  4.     public static void main(String[] args) {
  5.         MyInter m = Test1::a;
  6.     }
  7. }
  8. class Test2 extends Test1 {
  9. }
  10. @FunctionalInterface
  11. interface MyInter {
  12.     //该接口参数比上述的a方法参数数量多一个,除去第一个,其它类型一致(可兼容,如可以一个int,一个Integer)
  13.     //且Test1::a的Test1是该入参类型Test2的子类(不可颠倒)
  14.     //我的理解:最后执行的是Test1的a方法,是由入参Test2执行,Test2是子类,肯定可以执行父类的方法,所以ok
  15.     public void d(Test2 d,int param1,int param2);
  16. }

总结:指向任意类型实例方法的方法引用有两个要求:

  • 第一点:接口方法的参数比引用方法的参数多一个
  • 第二点:接口方法的第一个参数恰巧是调用引用方法的对象(其引用方法所在类或其父类的实例)

3. 默认方法

Java 8 新增了接口的默认方法。我们只需在方法名前面加个 default 关键字即可实现默认方法。

简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。

Java 8 的另一个特性是接口可以声明(并且可以提供实现)静态方法

  1. public class Car {
  2. public static void main(String[] args) {
  3. A a = new B();
  4. a.print();
  5. }
  6. }
  7. interface A{
  8. default void print(){
  9. System.out.println("-a-");
  10. }
  11. static void staticMethod(){
  12. System.out.println("-do-");
  13. }
  14. }
  15. class B implements A{
  16. @Override
  17. public void print() {
  18. A.super.print();
  19. A.staticMethod();
  20. System.out.println("-b-");
  21. }
  22. }

运行结果为

-a-

-do-

-b-

4. Stream类

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

  • foreach:迭代流中的每个数据
  1. Random random = new Random();
  2. random.ints().limit(10).forEach(System.out::println);

注:在stream的foreach中,无法使用break和continue终止循环。使用return;可以退出本次循环,不影响下一次循环

  • map:用于映射每个元素到对应的结果
  1. List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
  2. // 获取对应的平方数
  3. List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
  • filter:通过设置的条件过滤元素
  1. List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
  2. // 获取空字符串的数量
  3. int count = strings.stream().filter(string -> string.isEmpty()).count();
  • limit:会用获取指定数量的流
  1. //打印10条数据
  2. Random random = new Random();
  3. random.ints().limit(10).forEach(System.out::println);
  • sorted:用于对流进行排序
  1. //10个随机数排序
  2. Random random = new Random();
  3. random.ints().limit(10).sorted().forEach(System.out::println);
  • parallel并行程序:parallelStream是流并行处理程序的代替方法
  1. List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
  2. // 获取空字符串的数量
  3. int count = strings.parallelStream().filter(string -> string.isEmpty()).count();
  • Collectors:规约操作,例如将流转换为集合和聚合元素
  1. List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
  2. List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
  3. System.out.println("筛选列表: " + filtered);
  4. String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
  5. System.out.println("合并字符串: " + mergedString);

流搜索

  • findAny:查找任何一个就返回 Optional
  • findFirst:查找到第一个就返回 Optional
  • anyMatch:匹配上任何一个则返回 Boolean
  • allMatch:匹配所有的元素则返回 Boolean
  1. // 查找某一个枚举值
  2. public static SwitchEnum findAny(int type) {
  3. return Arrays.stream(SwitchEnum.values())
  4. .filter(switchEnum -> switchEnum.getType() == type)
  5. .findAny()
  6. .orElse(null);
  7. }
  8. // 匹配到第一个枚举值就返回
  9. public static SwitchEnum findFirst(String name) {
  10. return Arrays.stream(SwitchEnum.values())
  11. .filter(switchEnum -> switchEnum.getName().equals(name))
  12. .findFirst()
  13. .orElse(null);
  14. }
  15. // 枚举匹配
  16. public static boolean anyMatch(int type) {
  17. return Arrays.stream(SwitchEnum.values())
  18. //匹配任何一个则返回
  19. .anyMatch(switchEnum -> switchEnum.getType() == type);
  20. }
  21. // 枚举匹配
  22. public static boolean allMatch(String name) {
  23. return Arrays.stream(SwitchEnum.values())
  24. //匹配所有
  25. .allMatch(switchEnum -> switchEnum.getName().equals(name));
  26. }

5.Optional类

Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

Optional 类的引入很好的解决空指针异常。

方法 描述
static Optional empty() 返回空的 Optional 实例
boolean equals(Object obj) 判断其他对象是否等于 Optional
Optional filter(Predicate<? super predicate) 如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional
Optional flatMap(Function<? super T,Optional> mapper) 如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional
T get() 如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException
int hashCode() 返回存在值的哈希码,如果值不存在 返回 0
void ifPresent(Consumer<? super T> consumer) 如果值存在则使用该值调用 consumer , 否则不做任何事情
boolean isPresent() 如果值存在则方法会返回true,否则返回 false
Optional map(Function<? super T,? extends U> mapper) 如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional
static Optional of(T value) 返回一个指定非null值的Optional
static Optional ofNullable(T value) 如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional
T orElse(T other) 如果存在该值,返回值, 否则返回 other
T orElseGet(Supplier<? extends T> other) 如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果
T orElseThrow(Supplier<? extends X> exceptionSupplier) 如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常
String toString() 返回一个Optional的非空字符串,用来调试
  1. of() 和 ofNullable() 方法

    创建包含值的 Optional。

    两个方法的不同之处在于,如果你把 null 值作为参数传递进去,of() 方法会抛出 NullPointerException。

    明确对象不为 null 的时候使用 of()。

    如果对象即可能是 null 也可能是非 null,你就应该使用 ofNullable() 方法。

    Optional<User> opt = Optional.ofNullable(user);

  2. 返回对象值

  • get():从 Optional 实例中取回实际值对象的方法之一是使用 get() 方法,但如果值是null会抛异常,用之前要判断,isPresent()
  • orElse():如果有值则返回该值,否则返回传递给它的参数值.
  1. //如果user对象为空,返回user2对象
  2. User result = Optional.ofNullable(user).orElse(user2)
  • orElseGet():有值的时候返回值,如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口
  • 注意:orElse() 和 orElseGet() 的不同之处:当对象为空时无差异。当对象不为空时,orElse中的方法仍然会执行。
  1. User result = Optional.ofNullable(user).orElse(new User("extra@gmail.com", "1234"));
  2. User result2 = Optional.ofNullable(user).orElseGet(User::new);
  3. //user不为空,上面的构造方法仍然执行了

取值实例:

  1. //传统判断:
  2. if (user != null) {
  3. AddressEntity addressEntity = user.getAddressEntity();
  4. if (addressEntity != null) {
  5. String address = addressEntity.getAddress();
  6. if (address != null && address.length() > 3) {
  7. return address;
  8. }
  9. }
  10. }
  11. //optional
  12. return Optional.ofNullable(user)
  13. .map(u -> u.getAddressEntity())
  14. .map(a -> a.getAddress())
  15. .filter(s -> s.length() > 3)
  16. .orElse(null);

判断操作

  1. public static void doThing(String name) {
  2. if (name != null) {
  3. System.out.println(name);
  4. }
  5. }
  6. public static void doThingOptional(String name) {
  7. Optional.ofNullable(name)
  8. .ifPresent(System.out::println);
  9. }

6.时间日期API

旧版问题:

  • 非线程安全: java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
  • 设计很差 − Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类
  • 时区处理麻烦 − 日期类并不提供国际化,没有时区支持

Java 8 在 java.time 包下提供了很多新的 API。以下为两个比较重要的 API:

  • Local(本地) − 简化了日期时间的处理,没有时区的问题。
  • Zoned(时区) − 通过制定的时区处理日期时间。

6.1 LocalDateTime

常用方法 描述
LocalDateTime.now() 获取当前时间
of(int ...) 可以根据年月日时分,年月日时分秒,年月日时分秒毫秒等 获取时间
parse(CharSequence text) 根据文本创建时间,形如"2007-12-03T10:15:30"
toLocalDate() 获取当前日期对象
toLocalTime() 获取当前时间对象
getYear()
getMonth() 月(是个对象)
getMonthValue() 月值,eg:12
getDayOfMonth()、getDayOfYear()、getDayOfWeek() 当前是月、年、周的第几天
getHour()、getSecond()、getSecond()、getNano() 获取时、分、秒、毫秒
withYear(int year).. 替换时间,可以替换Year、Month、DayOfMonth、DayOfYear、Hour、Minute、Second、Nano
plusYears(long),plusMonth(long)... 一天后的时间,一年后的时间。(年,..,毫秒)
minYears(long),minMonths(long) 一天前的时间,(年,...,毫秒)
isAfter(LocalDataTime ldt) 对比当前对象时间是否在参数对象时间之后?返回boolean
isBefore(LocalDataTime ldt) 对比之前
isEqual(LocalDataTime ldt) 对比是否相等

实例:

  1. // 获取当前的日期时间
  2. LocalDateTime currentTime = LocalDateTime.now();
  3. System.out.println("当前时间: " + currentTime);
  4. LocalDate date1 = currentTime.toLocalDate();
  5. System.out.println("date1: " + date1);
  6. Month month = currentTime.getMonth();
  7. int day = currentTime.getDayOfMonth();
  8. int seconds = currentTime.getSecond();
  9. System.out.println("月: " + month +", 日: " + day +", 秒: " + seconds);
  10. LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
  11. System.out.println("date2: " + date2);
  12. // 12 december 2014
  13. LocalDate date3 = LocalDate.of(2014, Month.DECEMBER, 12);
  14. System.out.println("date3: " + date3);
  15. // 22 小时 15 分钟
  16. LocalTime date4 = LocalTime.of(22, 15);
  17. System.out.println("date4: " + date4);
  18. // 解析字符串
  19. LocalTime date5 = LocalTime.parse("20:15:30");
  20. System.out.println("date5: " + date5);

7. Base64

Java 8 内置了 Base64 编码的编码器和解码器。

Base64工具类提供了一套静态方法获取下面三种BASE64编解码器:

  • 基本:输出被映射到一组字符A-Za-z0-9+/,编码不添加任何行标,输出的解码仅支持A-Za-z0-9+/。
  • URL:输出映射到一组字符A-Za-z0-9+_,输出是URL和文件。
  • MIME:输出隐射到MIME友好格式。输出每行不超过76字符,并且使用'\r'并跟随'\n'作为分割。编码输出最后没有行分割

加密解密

  1. String text = "base64 in java8 lib";
  2. //编码
  3. String encode = Base64.getEncoder()
  4. .encodeToString(text.getBytes(StandardCharsets.UTF_8));
  5. System.out.println(encode);
  6. //解码
  7. String decode = new String(Base64.decode(encode), StandardCharsets.UTF_8);
  8. System.out.println(decode);

Java8特性的更多相关文章

  1. Java8特性之Lambda、方法引用以及Stream流

    Java 8 中的 Streams API 详解:https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/ Java笔记——Jav ...

  2. Java8 特性详解(一) Lambda

    为什么要使用lambda表达式 从函数式接口说起 理解Functional Interface(函数式接口)是学习Java8 lambda表达式的关键所在. 函数式接口的定义其实很简单:任何接口,如果 ...

  3. 详解Java8特性之新的日期时间 API

    详解Java8特性之新的日期时间 API http://blog.csdn.net/timheath/article/details/71326329 Java8中时间日期库的20个常用使用示例 ht ...

  4. Java笔记——Java8特性之Lambda、方法引用和Streams

    Java8已经推出了好一段时间了,而掌握Java8的新特性也是必要的,如果要进行Spring开发,那么可以发现Spring的官网已经全部使用Java8来编写示例代码了,所以,不学就看不懂. 这里涉及三 ...

  5. java8特性深入解读文章合集

    Java 8新特性列表 官方OpenJDK java8核心类库新特性列表 Lambda表达式 java8 lambda表达式被誉为java语言10年来最大的突破,给用户提供了scala和clojure ...

  6. Java8特性详解 lambda表达式 Stream

    1.lambda表达式 Java8最值得学习的特性就是Lambda表达式和Stream API,如果有python或者javascript的语言基础,对理解Lambda表达式有很大帮助,因为Java正 ...

  7. 第十七章 java8特性

    17.java8中Lambda表达式与Stream API的使用 17.1 Lambda 表达式(Lambda Expressions) 1课时 17.2 函数式(Functional)接口 1课时 ...

  8. Java8特性之Lambda、方法引用和Streams

    这里涉及三个重要特性: Lambda 方法引用 Streams ① Lambda 最早了解Lambda是在C#中,而从Java8开始,Lambda也成为了新的特性,而这个新的特性的目的,就是为了消除单 ...

  9. Java8特性详解 lambda表达式 Stream【转】

    本文转自http://www.cnblogs.com/aoeiuv/p/5911692.html 1.lambda表达式 Java8最值得学习的特性就是Lambda表达式和Stream API,如果有 ...

随机推荐

  1. 统计学习方法与Python实现(一)——感知机

    统计学习方法与Python实现(一)——感知机 iwehdio的博客园:https://www.cnblogs.com/iwehdio/ 1.定义 假设输入的实例的特征空间为x属于Rn的n维特征向量, ...

  2. B. Magic Stick

    题目:魔法棒 题意:可以对一个正数进行变换,如果数字是偶数,那么它可以变成3 * a / 2 如果这个数大于1,那么它可以变成a - 1 有两个数x和y,询问是否可以通过这些操作从x变成y,输出YES ...

  3. 笔记||Python3之字符串

    字符串是Python中最常用的数据类型.我们可以使用引号('或''或''')来创建字符串. 三引号特点:可以多行,也可以多行注释. a = 'hello world' a = "hello ...

  4. Django 09

    目录 多对多三种创建方式 全自动 纯手撸 半自动(推荐) form组件 校验数据 渲染标签 展示错误信息 validators校验器 钩子函数 补充 多对多三种创建方式 全自动 ManyToManyF ...

  5. Vmware Workstation虚拟机

    目录 一.虚拟机是什么? 二.虚拟机的作用: 三.虚拟机创建流程 四.新的虚拟机上安装系统 五.虚拟机里添加硬盘 六.磁盘分区 一.虚拟机是什么? 虚拟机指通过软件模拟的具有完整硬件系统功能的.运行在 ...

  6. 《吊打面试官》系列-ConcurrentHashMap & HashTable

    你知道的越多,你不知道的越多 点赞再看,养成习惯 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试点思维导图,也整理了很多我的文档,欢迎Star和 ...

  7. 用心整理 | Spring AOP 干货文章,图文并茂,附带 AOP 示例 ~

    Spring AOP 是 Java 面试的必考点,我们需要了解 AOP 的基本概念及原理.那么 Spring AOP 到底是啥,为什么面试官这么喜欢问它呢?本文先介绍 AOP 的基本概念,然后根据 A ...

  8. Golang 入门系列(十七)几个常见的并发模型——生产者消费者模型

    前面已经讲过很多Golang系列知识,包括并发,锁等内容,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.ht ...

  9. React中setState学习总结

    react中setState方法到底是异步还是同步,其实这个是分在什么条件下是异步或者同步. 1.先来回顾一下react组件中改变state的几种方式: import React, { Compone ...

  10. 2、手写Unity容器--第一层依赖注入

    这个场景跟<手写Unity容器--极致简陋版Unity容器>不同,这里构造AndroidPhone的时候,AndroidPhone依赖于1个IPad 1.IPhone接口 namespac ...