Java8虽然发布很久了,但由于稳定性极好一直作为大多数团队使用的版本,其相较于之前版本引入了哪些新特性呢?
Lambda & Functional Interface
Lambda表达式可以说是Java 8最大的卖点,将函数式编程引入了Java。Lambda允许把函数作为一个方法的参数,或者把代码看成数据
@FunctionalInterface
public interface Runnable
{
public abstract void run();
}
public class LambdaExamples
{
@Test
public void test(){
new Thread(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
误区:
认为的:通过匿名函数生成Runnable对象,传递给Thread
事实上:内部优化直接调用了匿名函数(invokedynamic指令)
方法引用::操作符
public class MethodReference
{
@Test
public void test(){
var val = List.of(1,2,3,4,5).stream().map(Object::toString)
.map(Integer::new).reduce((a,b)->a+b);
System.out.println(val);
}
}
Stream
一个Monad。函数式、流计算重磅炸弹。我们知道流是随着时间产生的数据序列,而Stream就是为一种序列提供顺序、并行的运算。例如支持函数式编程、管道的流计算等。
下面是一个简单的示例代码
List<String> lowCaloricDishesName = menu.stream()
//筛选出卡路里大于400的
.filter(d -> d.getCalories() < 400)
//抽取名字属性创建一个新的流
.map(Dish::getName)
//这个流按List类型返回
.collect(toList());
在这段代码 filter 和 map 操作被称为中间操作,中间操作会返回一个新的流,而 collect 则被称为终端操作只有终端操作才会让整个流执行并关闭。也就是说 每个流只能遍历一次 ,因为collect以后这个流就已经关闭了。
Optional
一个Monad。流计算必备工具,减少空值检查。另一个还没有支持,但比较重要的Monad
是Try。这个在实现AOP框架的程序中,我们已经使用到了。见之前讲流和Monad部分
接口的方法(static, default)
接口可以支持有默认方法和静态方法。
1.默认方法在接口中可以添加多个,并且 Java8 提供了很多对应的接口默认方法。当我们之前需要修改接口时候,此时对应需要修改全部实现该接口的类,而引入了接口默认方法解决了 Java8 以前版本接口兼容性问题,同时对于我们以后的程序开发,也可以在接口子类中直接使用接口默认方法,而不再需要再各个子类中各自实现响应接口方法。
2.静态方法只能通过接口来调用,即使用InterfaceName.staticMethod来调用它们
public interface Stream<T> extends BaseStream<T, Stream<T>> {
default Stream<T> takeWhile(Predicate<? super T> predicate)
{
...
foo();
}
public static<T> Stream<T> empty()
{
...
}
}
Nashorn JavaScript
在Java8中增加,可执行JS脚本,在Java11中标记为Deprecated(脚本这么多专门选JS没有优势)
public void test_engine()throws ScriptException {
var jscode = " [1,2,3].map(function(x){return x + 1;}).join('-');";
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn");
Object result = nashorn.eval(jscode);
System.out.println(result);
}
本地化日期处理升级
提供了Local和Zoned两种处理日期的方式,在新的API中不再允许mutable的操作(非线程安全);另外对时区采取更好的处理方法:如果用户的系统不考虑国际化,那么就用
Local的日期,如果考虑国际化,可以构造带时区的DateTime。
@Test
public void test_date(){
var date = LocalDate.of(2022, 2, 22);
var time = LocalTime.of(10, 55, 59);
var datetime = LocalDateTime.of(date, time);
var zoneDT = ZonedDateTime.of(datetime, ZoneId.of("Asia/Shanghai"));
}
内置了Base64工具
对0~255之间的字符,Base64编码是以4个可见字符去描述3个字符。会增加数据的体积,
但是因为所有字符都可以读,用Base64编码描述的字符串,在URL、XML中都不会被转义。Base64.Decoder和Base64.Encoder类