Java8及其与Spring4结合使用的部分总结

JAVA8新特性简介

一.Lambda表达式(也称为闭包)和函数式接口

     1. 它允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理.之前只能使用匿名内部类代替Lambda表达式,最简单的Lambda表达式可由逗号分隔的参数列表、->符号和语句块(大括号)组成.
     2. Lambda表达式有返回值,返回值的类型也由编译器推理得出.如果Lambda表达式中的语句块只有一行,则可以不用使用return语句.
     3. 某些特定的参数类型(如循环中的每个循环参数)是由编译器推理得出的,也可以显式指定该参数的类型.
     4. Lambda表达式可以引用类成员和局部变量(会将这些变量隐式得转换成final的).
     5. 函数接口指的是只有一个函数的接口,这样的接口可以隐式转换为Lambda表达式.java.lang.Runnable和java.util.concurrent.Callable是函数式接口的最佳例子.
     6. 注解@FunctionalInterface显式说明某个接口是函数式接口,但要注意:默认方法和静态方法不会破坏函数式接口的定义.

二.函数接口的默认方法和静态方法

      默认方法: 开发者可以在 不破坏二进制兼容性的前提下,往现存接口中添加新的方法,即不强制那些实现了该接口的类也同时实现这个新加的方法.
      默认方法和抽象方法的区别: 抽象方法需要实现,而默认方法不需要.接口提供的默认方法会被接口的实现类继承或者覆写.
      另一个有趣的特性是在接口中可以定义静态方法.

三.方法引用
    1. 参数类型:构造器       Class::new,或者更一般的形式:Class<T>::new.注意:这个构造器没有参数.
    2. 参数类型:静态方法   Class::static_method,注意:这个方法接受一个对象.
    3. 参数类型:某个类的成员方法   Class::method,注意:这个方法没有定义入参.
    4. 参数类型:某个实例对象的成员方法  instance::method,注意:这个方法接受一个对象.

四.重复注解
            允许在同一个地方多次使用同一个注解,@Repeatable注解定义重复注解.

五.更好的类型推断
            在很多场景下编译器可以推导出某个参数的具体的数据类型.

六.拓宽注解的应用场景
            注解几乎可以使用在任何元素上:局部变量、接口类型、超类和接口实现类,甚至可以用在函数的异常定义上.
            ElementType.TYPE_USER和ElementType.TYPE_PARAMETER是Java 8新增的两个注解,用于描述注解的使用场景.

七.方法的参数名称
            在运行时获得Java程序中方法的参数名称,Java8中这个特性是默认关闭的.
            如果你使用Maven进行项目管理,则可以在maven-compiler-plugin编译器的配置项中配置-parameters参数:

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-compiler-plugin</artifactId> 
    <version>3.1</version> 
    <configuration> 
        <compilerArgument>-parameters</compilerArgument> 
        <source>1.8</source> 
        <target>1.8</target> 
    </configuration>
</plugin>

八.java官方库加入Optional类

         提供了一些有用的接口来避免显式的null检查.
         isPresent():如果Optional实例持有一个非空值,则方法返回true,否则返回false.
         orElseGet():如果Optional实例持有null,则可以接受一个lambda表达式生成的默认值.
         map():该方法可以将现有的Opetional实例的值转换成新的值.
         orElse():该方法与orElseGet()方法类似,但是在持有null的时候返回传入的默认值.
         关于Optional类 对象的创建:
           1.创建空对象:

Optional<String> optStr =Optional.empty();

           2.创建不允许为空的对象, 当str为null的时候,将抛出NullPointException:

Optional<String> optStr =Optional.of(str);

           3.创建允许为空的对象, 如果str是null,则创建一个空对象:

Optional<String>optStr=Optional.ofNullable(str);

           注意:  1. Optional类在设计的时候就没有考虑将它作为类的字段使用.Optional是一个final类,未实现任何接口,所以在利用该类包装定义类的属性的时候,如果定义的类有序列化的需求,则因为Optional没有实现Serializable接口会导致被其的属性序列化失败.因此遇到此情况可采取以下替换策略:

private long phone; 
public Optional<Long> getPhone() { 
   return Optional.ofNullable(this.phone);
}

                   2.尽量避免使用get()方法:Optional是一个容器,既然为容器的话,那么就让他的操作不脱离容器:

//优化前 
String ref = request.getHeader("ref"); 
if (StringUtils.isNotEmpty(ref)) {
	request.getSession().setAttribute("ref", ref); 
} 
//java8 替代方案
Optional.ofNullable(request.getHeader("ref")).ifPresent(s -> { 
	request.getSession().setAttribute("ref", s);
});

                  3.尽量避免使用isPresent()方法, 该方法判断该对象是否存在,对于代码来说和直接写if(value != null)区别并不大.这里 更应该把isPresent()视为一个private方法,因为Optional内部其他实现是大多使用了该方法:

//待优化 
String rt = (String) session.getAttribute("ref"); 
if (rt == null){ 
	result.put("rt","/index"); 
}else { 
	result.put("rt",rt); 
} 
//java8替代方案 
Optional<String> rt = Optional.ofNullable((String) session.getAttribute("ref"));
result.put("rt",rt.orElse("/index"));

九.新增的Stream API(java.util.stream)将生成环境的函数式编程引入了Java库中

     (1) Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX 对 XML 解析的 Stream,也不是 Amazon Kinesis 对大数据实时处理的 Stream.
     Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation).
     (2) Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性.同时它提供串行和并行两种模式进行汇聚操作.
     (3) Stream之上的操作可分为中间操作和晚期操作:
          中间操作会返回一个新的stream——执行一个中间操作(例如filter)并不会执行实际的过滤操作,而是创建一个新的stream,并将原stream中符合条件的元素放入新创建的stream.
           晚期操作(例如forEach或者sum),会遍历stream并得出结果或者附带结果;在执行晚期操作之后,stream处理线已经处理完毕,就不能使用了.在几乎所有情况下,晚期操作都是立刻对stream进行遍历.
     (4) Stream的另一个价值是创造性地支持并行处理(parallel processing). 

构造流的几种常见方法:
// 1. 单个值
Stream stream = Stream.of("a", "b", "c");
// 2. 数组
String [] strArray = new String[] {"a", "b", "c"};
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
// 3. 集合
List<String> list = Arrays.asList(strArray);
stream = list.stream();

十.Date/Time API(JSR 310)

     新的java.time包 包含了所有关于日期、时间、时区、Instant(跟日期类似但是精确到纳秒)、duration(持续时间)

和时钟操作的类.
     Clock类使用时区来返回当前的纳秒时间和日期,可以替代System.currentTimeMillis()和TimeZone.getDefault().
     LocalDate类:LocalDate仅仅包含ISO-8601日历系统中的日期部分;
     LocalTime类:LocalTime则仅仅包含该日历系统中的时间部分.
     这两个类的对象都可以使用Clock对象构建得到.
     LocalDateTime类:包含LocalDate和LocalTime的信息,但是不包含ISO-8601日历系统中的时区信息.
     ZonedDateTime类:保存有ISO-8601日期系统的日期和时间,而且有时区信息.
     Duration类:持有的时间精确到秒和纳秒,可以很好的计算两个日期.

十一.Nashorn JavaScript引擎
       可以在JVM上开发和运行JS应用,是javax.script.ScriptEngine的另一个实现版本,这类Script引擎遵循相同的规则,允许Java和JavaScript交互使用.

   
十二.Base64
       对Base64编码的支持已经被加入到Java 8官方库中,这样不需要使用第三方库就可以进行Base64编码.

final String text = "Base64 finally in Java 8!";
String encodeStr = Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8));
String str = new String(Base64.getDecoder().decode(encodeStr),StandardCharsets.UTF_8);

      同时新的Base64 API也支持URL和MINE的编码解码:
      Base64.getUrlEncoder() / Base64.getUrlDecoder();
      Base64.getMimeEncoder() / Base64.getMimeDecoder().

十三.并行数组

      用于支持并行数组处理.最重要的方法是parallelSort(),可以显著加快多核机器上的数组排序.

Arrays.parallelSetAll(arrayOfLong, index -> ThreadLocalRandom.current().nextInt(1000000));
Arrays.parallelSort(arrayOfLong);
Arrays.stream(arrayOfLong ).limit( 10 ).forEach( i -> System.out.print( i + " " ));

十四.Nashorn引擎:jjs
      jjs是一个基于标准Nashorn引擎的命令行工具,可以接受js源码并执行.

 

十五.类依赖分析器:jdeps
      它可以展示包层级和类层级的Java类依赖关系,它以.class文件、目录或者Jar文件为输入,然后会把依赖关系输出到控制台.

十六.JVM的新特性
      使用Metaspace(JEP 122)代替持久代(PermGen space).
      在JVM参数方面,使用-XX:MetaSpaceSize和-XX:MaxMetaspaceSize代替原来的-XX:PermSize和-XX:MaxPermSize.

Spring4与Java8新特性

  • 前提

           Spring4框架本身是由Java 8编译器编译的,编译时使用的是生成Java 6字节码的编译命令选项.因此可以Java6、7或者8来编译运行Spring 4.x的应用,保证java8的向下兼容性.

  • Spring4与Java8的Lambda表达式

           因为Spring框架早在Java 8正式给函数式接口下定义之前就已经实际使用了函数式接口,因此在Spring里使用lambda表达式非常容易.

  • Spring 4和Java8的时间与日期API

           Spring有一个数据转换框架,它可以使字符串和Java数据类型相互转换.Spring4升级了这个转换框架以支持Java 8日期与时间API里的那些类.如:

@RequestMapping("/date/{localDate}") 
public String getDateStr(@DateTimeFormat(iso=ISO.DATE) LocalDate localDate){ 
      return localDate.toString(); 
}
  • Spring 4与重复注解 

      Java8增加了对重复注解的支持,Spring4也同样支持.特殊的是,Spring4支持对注解@Scheduled和@PropertySource的重复.

@PropertySource("test1.properties")
@PropertySource("test2.properties")
public class Application {

     @Autowired
     private Environment env;
        
     System.out.println(env.getProperty("p1"));
     System.out.println(env.getProperty("p2"));
     ...
} 
  • Java8的Optional<T>与Spring4

          消除NullPointerExceptions的方式之一是确保方法总是返回一个非空值.
          java8之前的写法如下:

User user=userService.getUserById("shilei");
// 避免空指针错误
if(customer != null) {
   customer.getName(); 
}

          java8的写法如下:

Optional<User> opt = userService.getUserById("shilei");
if(opt.isPresent()) {
   User user = opt.get();
   user.getName();
}

        使用Optional优势: 有缺陷版本不会被编译,开发者必须显式地检查这个Optional类型对象是否有值.确保开发者不用查阅Javadoc或者使用Debug断点查看就能知道某个方法可以返回null; 或者可以把一个null值传给某方法.编译器和方法签名有助于开发者明确知道某个值是Optional类型.

 

         Spring4存在两种支持java8 Optional的方式 如下:

//第一种 使用@Autowired时:
public class UserService { 
    @Autowired 
    Optional<UserService> userService;
    userService.ifPresent(s -> {
        //逻辑代码 
    });
}
//第二种:用于Spring MVC框架中,表示某个处理方法的参数可选.
@RequestMapping("getData")
@ResponseBody
private void getData(Optional<String> type) {
    System.out.println(type.isPresent());
    type.ifPresent(s -> {System.out.println(type.get());});
}
  • 参数名发现机制

          在Java7及之前的版本中,-debug选项不会保留抽象方法的参数名,这会导致Spring Data这类基于Java接口自动生成其资源库实现的工程就会出现问题.如下:

interface UserService extends BaseService {
	@Query("select * from User u where u.name =:name")
	List<User> findByName(@Param("name") String name);
}

         而Java8支持在编译后的代码中保留方法的参数名,只要在编译时指定了–parameters标记,Java8编译器就会把参数名写入.class文件中;使用–parameters选项后,Spring Data也就能自动找到抽象方法的参数名;如下:

interface UserService extends BaseService {
	@Query("select * from User u where u.name =:name")
	List<User> findByName(String name);
}

          这意味着Spring4也可以从方法中提取参数名,从而使SpringMVC代码更为简洁,由如下:

@RequestMapping("/getUser/{userId}")
public Account getUser(@PathVariable("userId") String userId){...}

          变成:

@RequestMapping("/getUser/{userId}")
public Account getUser(@PathVariable String userId){...}

个人总结

      以上便是本人针对java8及其与Spring4结合使用的部分总结,同时个人认为java8中新增的一些特性却有其好处及优势,但本身也是一个工具,如果之前JDK版本中的的方法在使用时更为简单的话,使用之前的版本中的部分方法也未尝不可.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值