Java 8中其他的三个语言特性的更新,分别是重复注解(repeated annotation)、类型注解(type annotation)和通用目标类型推断(generalized target-type inference)。
A.1 注解
Java 8在两个方面对注解机制进行了改进,分别为:
你现在可以定义重复注解
使用新版Java,你可以为任何类型添加注解
Java中的注解是一种对程序元素进行配置,提供附加信息的机制(注意,在Java 8之前,只有声明可以被注解)。换句话说,它是某种形式的语法元数据(syntactic metadata)
A.1.1 重复注解
创建一个重复注解:
(1) 将注解标记为@Repeatable
(2) 提供一个注解的容器
package com.h.java8;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ValidateGroup {
ValidateFiled[] value();
}
package com.h.java8;
import java.lang.annotation.*;
@Repeatable(ValidateGroup.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ValidateFiled {
/**
* 参数索引位置
*/
int index() default -1;
/**
* 如果参数是基本数据类型或String ,就不用指定该参数,如果参数是对象,要验证对象里面某个属性,就用该参数指定属性名
*/
String filedName() default "";
/**
* 正则验证
*/
String regStr() default "";
/**
* 是否能为空 , 为true表示不能为空 , false表示能够为空
*/
boolean notNull() default false;
/**
* 不为空(只针对CharSequence,Collection,Map,Dictionary,Array)
*/
boolean notEmpty() default false;
/**
* 是否不为空白串(只针对CharSequence) 为true表示不能为空 , false表示能够为空
*
* @return
*/
boolean notBlank() default false;
/**
* 是否能为空 , 为true表示不能为空 , false表示能够为空
*/
int maxLen() default -1;
/**
* 最小长度 , 用户验证字符串
*/
int minLen() default -1;
/**
* 最大值 ,用于验证数字类型数据
*/
int maxVal() default -1;
/**
* 最小值 ,用于验证数值类型数据
*/
int minVal() default -1;
/**
* 提示信息:校验失败时候自动拼装
*/
String msg() default "";
}
package com.h.java8;
import com.dafycredit.common.constants.RegexConsts;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Map;
public class TestMain2 {
public static void main(String[] args) {
/**
* Java8之前的版本禁止对同样的注解类型声明多次
*/
}
/**
* Java8之前的版本的参数验证
* @param paramMap
*/
@ValidateGroup({
@ValidateFiled(index = 0, filedName = "deviceId", notBlank = true, msg = "设备id不能为空"),
@ValidateFiled(index = 0, filedName = "userName", regStr = RegexConsts.REGEX_NEW_MOBILE_EXACT, notBlank = true, msg = "无效的用户名"),
@ValidateFiled(index = 0, filedName = "password", notBlank = true, msg = "密码不能为空")})
@RequestMapping(value = "account/login", method = {RequestMethod.POST})
@ResponseBody
public void login1(@RequestBody Map<String, String> paramMap) {
}
/**
* Java8后的版本的参数验证
* @param paramMap
*/
@ValidateFiled(index = 0, filedName = "deviceId", notBlank = true, msg = "设备id不能为空")
@ValidateFiled(index = 0, filedName = "userName", regStr = RegexConsts.REGEX_NEW_MOBILE_EXACT, notBlank = true, msg = "无效的用户名")
@ValidateFiled(index = 0, filedName = "password", notBlank = true, msg = "密码不能为空")
@RequestMapping(value = "account/login", method = {RequestMethod.POST})
@ResponseBody
public void login2(@RequestBody Map<String, String> paramMap) {
}
}
可以把这种新的机制看成是一种语法糖,它提供了Java程序员之前利用的惯用法类似的功能。为了确保与反射方法在行为上的一致性,注解会被封装到一个容器中。Java API中的getAnnotation(Class<T>annotation-Class)方法会为注解元素返回类型为T的注解。如果实际情况有多个类型为T的注解,该方法的返回到底是哪一个呢?
Method method = TestMain2.class.getMethod("login2", Map.class);
ValidateFiled[] validateFileds = method.getAnnotationsByType(ValidateFiled.class);
Arrays.asList(validateFileds).forEach(System.out::println);
A.1.2 类型注解
从Java 8开始,注解已经能应用于任何类型。这其中包括new操作符、类型转换、instanceof检查、泛型类型参数,以及implements和throws子句。
@NonNull String name = person.getName();
List<@NonNull Car> cars = new ArrayList<>();
Java 8并未提供官方的注解或者一种工具能以开箱即用的方式使用它们。它仅仅提供了一种功能,你使用它可以对不同的类型添加注解。幸运的是,这个世界上还存在一个名为Checker的
框架,它定义了多种类型注解,使用它们你可以增强类型检查。如果对此感兴趣,我们建议你看看它的教程,地址链接为:http://www.checker-framework.org。
A.2 通用目标类型推断
/**
*cleanCars (java.util.List<Car>)cannot be applied to(java.util.List<java.lang.Object>)
*/
static void cleanCars(List<Car> cars) {
}
cleanCars(Collections.emptyList());
/**
*Java 8中,目标类型包括向方法传递的参数,因此你不再需要提供显式的泛型参数:
*/
List<Car> cleanCars = dirtyCars.stream()
.filter(Car::isClean)
.collect(Collectors.toList());