目录
1,Lambda表达式
2,方法引用
3,stream
4,Optional
5,Nashorn JavaScript
6,日期时间
7,Base64编码
Java8即JDK1.8新增了很多新的特性,一起来探索一下吧。
Java8支持Lambda表达式,来支持函数式编程,将函数作为方法的参数。经常用于代替匿名内部类的使用。函数接口可以使用lambda表达式
函数接口,接口有且只有一个抽象方法,并且在类上标记注解@FunctionalInterface注解,表示该类是函数接口。另外,只要接口是只有一个抽象函数的接口,虚拟机会自动判断为函数接口,但是为了理解清晰,最好在接口函数上增加@FunctionalInterface注解,以示区分。
函数接口可以转化为Lambda表达式,如:
public static void main(String[] args) {
Predicate predicate = n -> n%2 == 0;
log.info(predicate.test(3)+"");
Runnable runnable = ()->{
while(true){
log.info(System.currentTimeMillis()+"");
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Comparator comparator = (a,b) -> a.compareTo(b);
}
当不符合函数接口规则的接口,标记为函数接口,会编译报错。
default方法,jdk8可以允许接口有Default默认的已实现的方法存在,接口的实现可以重写default方法,也可以补充协议default方法。当接口中有多个方法定义,但是又要将接口标记为函数接口时,可以主要的一个方法外的其他改为default方法。
Lambda表达式,格式为(parameters) -> {statements} 或者 parameter -> statement,语句的特性包括:
代码样例如下:
public class Java8Test {
static void main(String[] args) {
//lambda表达式,初始化Java8Interface接口的实例,一个参数一个语句
I1 i1 = a -> Math.sqrt(a);
Double sqrt = i1.sqrt(4);
Double pow2 = i1.pow2(2);
System.out.println(sqrt);
System.out.println(pow2);
//lambda表达式,一个多个参数多个语句
I2 i2 = (a, b) -> {return Math.pow(a, b);};
Double cbrt = i2.cbrt(4);
double pow = i2.pow(2,3);
System.out.println(cbrt);
System.out.println(pow);
}
}
//函数式接口,有且只有一个抽象方法
@FunctionalInterface
interface I1 {
//有且只有一个抽象方法
Double sqrt(Integer a);
//default方法
default Double pow2(Integer a){
return Math.pow(a, 2);
}
}
@FunctionalInterface
interface I2 {
//有且只有一个抽象方法
Double pow(Integer a, Integer b);
//default方法
default Double cbrt(Integer a){
return Math.cbrt(a);
}
}
输出结果:
2.0
4.0
1.5874010519681996
8.0
变量的作用域,lambda表达式中的可以访问外部的变量,但是不可以修改外部的变量,表达式内的变量也不可以和外部的变量同名。否则编译报错。
Java8提供了新的方法引用方式“::”,功能等价于“.”,通过实例来了解Java8如何通过新的方式饮用方法。
引用构造函数时,需借助于Supplier
public class Apple {
private static final Logger log = LoggerFactory.getLogger(Apple.class);
public Apple(){
log.info("create Apple object");
}
static void deck(Apple apple){
log.info("apple deck "+apple+", wow beautiful");
}
void call(Apple apple){
log.info(this+" calls "+apple);
}
void juicing(){
log.info("juicing apple "+this);
}
public static void main(String[] args){
//调用构造函数,借助于Supplier类,实现构造方法的引用
Supplier supplier = Apple::new;
Apple apple = supplier.get();
List appleList = Arrays.asList(apple);
//Apple类静态方法deck引用,foreach也是java8新特性,遍历
appleList.forEach(Apple::deck);
//特定类的任意对象方法引用,类型Apple的遍历对象的juicing方法引用
appleList.forEach(Apple::juicing);
//指定对象的方法引用,调用apple1的call方法,参数为遍历对象,
Supplier supplier1 = Apple::new;
Apple apple1 = supplier1.get();
appleList.forEach(apple1::call);
}
}
输出结果为
2019-08-13 11:17:17 [main] [INFO ] [com.weihao.java8.Apple]create Apple object
2019-08-13 11:17:17 [main] [INFO ] [com.weihao.java8.Apple]apple deck com.weihao.java8.Apple@53aad5d5, wow beautiful
2019-08-13 11:17:17 [main] [INFO ] [com.weihao.java8.Apple]juicing apple com.weihao.java8.Apple@53aad5d5
2019-08-13 11:17:17 [main] [INFO ] [com.weihao.java8.Apple]create Apple object
2019-08-13 11:17:17 [main] [INFO ] [com.weihao.java8.Apple]com.weihao.java8.Apple@8317c52 calls com.weihao.java8.Apple@53aad5d5
Java8新增了stream操作,stream是一个来自数据源的元素队列,并支持聚合计算等操作。stream可以类似于sql一样,对集合元素进行查询,运算,排序,聚合等。
stream的中间操作会返回中间操作的结果,结果是stream对象本身,迭代方式是通过访问者模式实现的内部迭代。通过代码来了解具体的作用。
public class StreamTest {
private static final Logger log = LoggerFactory.getLogger(StreamTest.class);
public static void main(String[] args) {
//借助Supplier,引用Random构造器,初始化Random实例
Supplier supplier =Random::new;
Random random = supplier.get();
//随机int数组
//boxed(),返回流的元素组成的流,元素都是Integer包装的
//collect(),在流的元素上执行聚合操作,Collectors.toList(),返回将输入元素积累成List的Collector
List list = random.ints(30,1,100).boxed().collect(Collectors.toList());
log.info("random ary:"+list.toString());
log.info("random ary length:" + list.stream().count());
log.info("random ary distinct length:" + list.stream().distinct().count());
log.info("random ary distinct and greater or equal to 50:"+list.stream().distinct().filter(a -> a >= 50).collect(Collectors.toList()).toString());
log.info("random ary skip 10 and limit 10 result:"+ list.stream().sorted().skip(10).limit(10).collect(Collectors.toList()));
//遍历
//list.stream().forEach(a -> log.info(a+""));
log.info("random ary distributed and sorted result:"+list.stream().map(i -> i/10).sorted().collect(Collectors.toList()).toString());
log.info("random ary distributed and group result:"+list.stream().collect(Collectors.groupingBy(i -> i/10)).toString());
log.info("random ary distributed and group ,count result:"+list.stream().collect(Collectors.groupingBy(i -> i/10, Collectors.counting())).toString());
IntSummaryStatistics summaryStatistics = list.stream().mapToInt(i -> i).summaryStatistics();
log.info("random ary max:"+summaryStatistics.getMax());
log.info("random ary min:"+summaryStatistics.getMin());
log.info("random ary sum:"+summaryStatistics.getSum());
log.info("random ary average:"+summaryStatistics.getAverage());
log.info("random ary count:"+summaryStatistics.getCount());
//增加元素100
log.info("add elements 100");
summaryStatistics.accept(100);
log.info("random ary max:"+summaryStatistics.getMax());
log.info("random ary min:"+summaryStatistics.getMin());
log.info("random ary sum:"+summaryStatistics.getSum());
log.info("random ary average:"+summaryStatistics.getAverage());
log.info("random ary count:"+summaryStatistics.getCount());
//合并其他统计结果
log.info("combine other statistics");
summaryStatistics.combine(random.ints(10,0,100).summaryStatistics());
log.info("random ary max:"+summaryStatistics.getMax());
log.info("random ary min:"+summaryStatistics.getMin());
log.info("random ary sum:"+summaryStatistics.getSum());
log.info("random ary average:"+summaryStatistics.getAverage());
log.info("random ary count:"+summaryStatistics.getCount());
//并行处理
log.info("random ary parallel filter less than 10:"+list.parallelStream().filter(i -> i < 10).collect(Collectors.toList()).toString());
}
}
代码执行结果如下
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary:[81, 90, 99, 57, 64, 54, 89, 44, 47, 9, 13, 71, 87, 85, 79, 75, 91, 34, 65, 39, 13, 92, 93, 30, 33, 6, 12, 24, 30, 62]
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary length:30
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary distinct length:28
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary distinct and greater or equal to 50:[81, 90, 99, 57, 64, 54, 89, 71, 87, 85, 79, 75, 91, 65, 92, 93, 62]
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary skip 10 and limit 10 result:[39, 44, 47, 54, 57, 62, 64, 65, 71, 75]
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary distributed and sorted result:[0, 0, 1, 1, 1, 2, 3, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9]
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary distributed and group result:{0=[9, 6], 1=[13, 13, 12], 2=[24], 3=[34, 39, 30, 33, 30], 4=[44, 47], 5=[57, 54], 6=[64, 65, 62], 7=[71, 79, 75], 8=[81, 89, 87, 85], 9=[90, 99, 91, 92, 93]}
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary distributed and group result:{0=2, 1=3, 2=1, 3=5, 4=2, 5=2, 6=3, 7=3, 8=4, 9=5}
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary max:99
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary min:6
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary sum:1668
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary average:55.6
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary count:30
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]add elements 100
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary max:100
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary min:6
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary sum:1768
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary average:57.03225806451613
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary count:31
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]combine other statistics
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary max:100
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary min:6
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary sum:2223
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary average:54.21951219512195
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary count:41
2019-08-13 15:26:30 [main] [INFO ] [com.weihao.java8.StreamTest]random ary parallel filter less than 10:[9, 6]
从上面的实例中可以看到stream的功能十分强大。流式的处理,类似sql的查询统计分析等功能,简洁的代码书写方式,也可以看到Java发展的方向。
Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
Optional 类的引入很好的解决空指针异常。
因为新增的是API,通过代码实例来看Optional的用法。
@Test
public void testOptional(){
//创建null optional
Optional emptyOptional = Optional.empty();
//创建不为空的optional, of()方法,不能传null
Optional optionalS = Optional.of("1");
//创建空字符串的optional
Optional optionalS1 = Optional.of("");
//创建null的optional
Optional optionalS2 = Optional.ofNullable(null);
log.info("isPresent");
log.info(emptyOptional.isPresent()+"");
log.info(optionalS.isPresent()+"");
log.info(optionalS1.isPresent()+"");
log.info(optionalS2.isPresent()+"");
log.info("toString");
log.info(emptyOptional.toString());
log.info(optionalS.toString());
log.info(optionalS1.toString());
log.info(optionalS2.toString());
log.info("get");
try{
log.info(emptyOptional.get());
}catch (Exception e){
log.info("emptyOptional.get() ERROR");
}
log.info(optionalS.get().toString());
log.info(optionalS1.get().toString());
try{
log.info(optionalS2.get());
}catch (Exception e){
log.info("optionalS2.get() ERROR");
}
//如果存在,执行lambda表达式
log.info("ifPresent");
emptyOptional.ifPresent(a -> log.info(a));
optionalS.ifPresent(a -> log.info(a));
optionalS1.ifPresent(a -> log.info(a));
optionalS2.ifPresent(a -> log.info(a));
//过滤
log.info("filter");
log.info(emptyOptional.filter(s -> !s.isEmpty()).isPresent()+"");
log.info(optionalS.filter(s -> !s.isEmpty()).isPresent()+"");
log.info(optionalS1.filter(s -> !s.isEmpty()).isPresent()+"");
log.info(optionalS2.filter(s -> !s.isEmpty()).isPresent()+"");
//如果optional存在,则返回optional的map结果,如果不存在则返回空optional
log.info("flatMap: "+optionalS.flatMap(a -> Optional.of("map"+a)).toString());
//不存在返回其他
log.info("orElse: "+optionalS.orElse("0"));
//不存在返回其他对象
log.info("orElseGet: "+optionalS.orElseGet(String::new));
try{
log.info("orElseThrow: "+ optionalS2.orElseThrow(RuntimeException::new));
}catch (Exception e){
log.info("catch exception",e);
}
}
代码执行结果
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]isPresent
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]false
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]true
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]true
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]false
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]toString
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]Optional.empty
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]Optional[1]
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]Optional[]
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]Optional.empty
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]get
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]emptyOptional.get() ERROR
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]1
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]optionalS2.get() ERROR
2019-08-13 16:14:29 [main] [INFO ] [com.weihao.TestJava8]ifPresent
2019-08-13 16:14:30 [main] [INFO ] [com.weihao.TestJava8]1
2019-08-13 16:14:30 [main] [INFO ] [com.weihao.TestJava8]
2019-08-13 16:14:30 [main] [INFO ] [com.weihao.TestJava8]filter
2019-08-13 16:14:30 [main] [INFO ] [com.weihao.TestJava8]false
2019-08-13 16:14:30 [main] [INFO ] [com.weihao.TestJava8]true
2019-08-13 16:14:30 [main] [INFO ] [com.weihao.TestJava8]false
2019-08-13 16:14:30 [main] [INFO ] [com.weihao.TestJava8]false
2019-08-13 16:14:30 [main] [INFO ] [com.weihao.TestJava8]flatMap: Optional[map1]
2019-08-13 16:14:30 [main] [INFO ] [com.weihao.TestJava8]orElse: 1
2019-08-13 16:14:30 [main] [INFO ] [com.weihao.TestJava8]orElseGet: 1
2019-08-13 16:14:30 [main] [INFO ] [com.weihao.TestJava8]catch exception
java.lang.RuntimeException: null
at java.util.Optional.orElseThrow(Optional.java:290)
at com.weihao.TestJava8.testOptional(TestJava8.java:78)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
Nashorn 一个 javascript 引擎。
从JDK 1.8开始,Nashorn取代Rhino(JDK 1.6, JDK1.7)成为Java的嵌入式JavaScript引擎。Nashorn完全支持ECMAScript 5.1规范以及一些扩展。它使用基于JSR 292的新语言特性,其中包含在JDK 7中引入的 invokedynamic,将JavaScript编译成Java字节码。与先前的Rhino实现相比,这带来了2到10倍的性能提升。
jjs
jjs是一个Java命令,接受Javascription代码或者文件为参数,并执行代码。
命令行使用jjs如下
[root@ecs-7bc6-0001 ~]# jjs
jjs> print("hello world");
hello world
jjs> ^C[root@ecs-7bc6-0001 ~]#
使用jjs执行javascription文件,首先新建a.js文件如下:
function f(a){
print("hello "+a);
}
f("world");
执行js程序代码
[root@ecs-7bc6-0001 ~]# jjs a.js
hello world
Java中执行JavaScript,通过以下样例实现校验用户的身份证,手机号码是否合法。
@Test
public void testJavaScript() throws ScriptException {
//创建脚本引擎管理
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
//获取脚本引擎管理
NashornScriptEngine scriptEngine = (NashornScriptEngine) scriptEngineManager.getEngineByName("nashorn");
//创建脚本参数
Map map = new HashMap<>();
map.put("idcardNO", "610300199801016666");
map.put("phone", "18888888888");
Bindings bindings = new SimpleBindings();
bindings.put("user",map);
//定义脚本
String javascript = "" +
"var idcardReg = /^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$|^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$/;" +
"var phoneReg = /^1[3456789]\\d{9}$/;" +
" var a = idcardReg.test(user.idcardNO);" +
" var b = phoneReg.test(user.phone);" +
"function f(c,d){return c&&d};" +
"f(a,b);";
//编译脚本
CompiledScript compiledScript = scriptEngine.compile(javascript);
//执行脚本
Object obj = compiledScript.eval(bindings);
log.info(obj.toString());
}
JavaScript中调用Java,返回当前时间。
@Test
public void testJavaScriptCallJava() throws ScriptException {
//创建脚本引擎管理
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
//获取脚本引擎管理
NashornScriptEngine scriptEngine = (NashornScriptEngine) scriptEngineManager.getEngineByName("nashorn");
//创建脚本参数
//定义脚本
String javascript = "var SimpleDateFormat = Java.type('java.text.SimpleDateFormat');" +
"var Date = Java.type('java.util.Date');" +
"function currentTime(){" +
"var sdf = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss');" +
"var cur = new Date();" +
"return sdf.format(cur);" +
"};" +
"currentTime();";
//编译脚本
CompiledScript compiledScript = scriptEngine.compile(javascript);
//执行脚本
Object obj = compiledScript.eval();
log.info(obj.toString());
}
Java8引入了新的日期和时间处理Api,针对之前版本的日期时间的优化API,主要包括:
Local,简化日期时间的处理,没有时区问题。
Zoned,通过制定的时区处理日期和时间。
同样,通过具体样例来了解新的日期和时间:
@Test
public void testNewDateAndTime(){
LocalDateTime current = LocalDateTime.now();
//格式化
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
log.info(dtf.format(current));
current.getDayOfMonth();
current.plusDays(1);
log.info(dtf.format(current));
current.minusHours(20);
log.info(dtf.format(current));
log.info(dtf.parse("2018-08-08 12:00:00").toString());
}
输出结果如下
2019-08-13 18:13:42 [main] [INFO ] [com.weihao.TestJava8]2019-08-13 18:13:42
2019-08-13 18:13:42 [main] [INFO ] [com.weihao.TestJava8]2019-08-13 18:13:42
2019-08-13 18:13:42 [main] [INFO ] [com.weihao.TestJava8]2019-08-13 18:13:42
2019-08-13 18:13:42 [main] [INFO ] [com.weihao.TestJava8]{},ISO resolved to 2018-08-08T12:00
Java8支持了Base64编码,不需要再引入其他第三方库支持Base64编码了,如下:
@Test
public void testBase64(){
String a = "Hello World!";
String base64String = new String(Base64.getEncoder().encode(a.getBytes(Charsets.UTF_8)), Charsets.UTF_8);
log.info("encode: "+ base64String);
byte[] bytes = Base64.getDecoder().decode(base64String);
log.info("decode:" + new String(bytes, Charsets.UTF_8));
}
运行结果如下:
2019-08-13 18:11:28 [main] [INFO ] [com.weihao.TestJava8]encode: SGVsbG8gV29ybGQh
2019-08-13 18:11:28 [main] [INFO ] [com.weihao.TestJava8]decode:Hello World!
(完)(^_^)