Java8的新特性主要表现在:语言、编辑器、库、工具、运行时
基本语法:parameter->expression body
MathOperation addition = (int a, int b) -> a + b;
Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );
定义:只有一个函数的接口。这样的接口可以隐式转化为Lambda表达式。值得注意的是:默认方法和静态方法不会破坏函数接口的定义。
可以显示说明某个函数是函数接口。如:
@FunctionalInterface
public interface FunctionalDefaultMethods {
void method();
default void defaultMethod() {
}
}
默认方法可以不破坏二进制兼容的情况下,往现有的接口中添加方法。即:不强求实现该接口的类实现这个默认方法。当然实现类也可以继承或重写这个默认方法。
但是静态方法和默认方法有一定的区别:
构造器引用:语法是Class::new。值得注意的是,该构造器没有参数。如:HashSet::new。
静态方法引用:语法是Class::static_method。这个方法接受一个Class类型的参数。
特定类的任意对象的方法引用:语法是Class::method。这个方法没有参数。
特定对象的方法引用:语法是instance:method。这个方法接受一个instance对应的Class类型的参数。
Java8允许在同一位置声明多个注解。重复注解机制需要使用@Repeatable注解。
public class RepeatingAnnotations {
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Filters{
Filter[] value();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Filters.class)
public @interface Filter{
String value();
}
@Filter("filter1")
@Filter("filter2")
public interface Filterable{
}
public static void main(String[] args) {
for(Filter filter: Filterable.class.getAnnotationsByType(Filter.class)){
System.out.println(filter.value());
}
}
}
Filter使用@Repetable(Filers.class)修饰,Filters是存放Filter注解的容器。反射API提供getAnnotationByType()返回某个类型的重复注解。
注解可以使用到局部变量、接口类型、函数的异常定义等上。
为了在运行时获得方法的参数名称,Java8可以在语法层面(利用反射API和Parameter.getName()方法)、字节码层面(使用新的javac编译器以及-parameter参数)提供支持。
为了解决空指针异常问题。常用的方法有:
.isPresent()。如果存在值,返回true
.orElse()。如果有值,返回当前值,如果没有值,返回other。
.of()。如果不为null,返回一个指定值的Optional,否则报异常。
.ofNullable()。如果不为null,返回一个指定值的Optional,否则返回一个空的Optional。
.get()。如果有值,返回当前值,如果没有值,返回NoSuchElementException。
常用的方法:
.stream()。返回顺序流,集合作为其源。
.parallelStream()。返回并行数据流,集合作为其源。
.filter()。方法用于消除基于标准元素。
.map()。方法用于映射每个元素对应的结果
.forEach()。方法遍历流中的每一个元素。
.limit()。方法用于减少流的大小。
.sorted()。方法用于流排序。
.collect()。方法是终端操作,通常出现在管道传输结束标记流的结束。
public void test(){
List strings=Arrays.asList("abc","","ba","efg","abcd","","jkl");
List list=strings.stream().filter(n->!"".equals(n)).limit(3).collect(Collectors.toList());
list.forEach(n->System.out.println(n));
}
Clock:通过指定一个时区,获取当前时刻、日期与时间
LocalDateTime:包含了LocalDate和LocalTime,但是不包含ISO-8601日历系统中的时区信息。
ZonedDateTime:带时区日期时间处理。
ZonedDateTime date1 = ZonedDateTime.parse("2007-12-03T10:15:30+05:30[Asia/Karachi]");
ChronoUnit:可以代替Calendar的日期操作。
LocalDate today = LocalDate.now();
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
Period:处理有关基于时间的日期数量。
LocalDate date1 = LocalDate.now();
LocalDate date2 = date1.plus(3, ChronoUnit.DAYS);
Period period = Period.between(date1, date2);
Duration:处理有关基于时间的时间量。
TemporarlAdjuster:做日期数学计算。
LocalDate date1 = LocalDate.now();
LocalDate nextTuesday = date1.with(TemporalAdjusters.next(DayOfWeek.TUESDAY));
可以在JVM上开发和运行JS。
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName( "JavaScript" );
System.out.println( engine.getClass().getName() );
System.out.println( "Result:" + engine.eval( "function f() { return 1; }; f() + 1;" ) );
inal String text = "Base64 finally in Java 8!";
final String encoded = Base64.getEncoder().encodeToString( text.getBytes( StandardCharsets.UTF_8 ) );
final String decoded = new String( Base64.getDecoder().decode( encoded ),StandardCharsets.UTF_8 );
比较重要的方法是parallelSort。
long[] arrayOfLong=new long[20000];
Arrays.parallelSetAll(arrayOfLong,index->ThreadLocalRandom.current().nextInt(1000000));
Arrays.stream(arrayOfLong).limit(10).forEach(i-> System.out.print(i+""));
Arrays.parallelSort(arrayOfLong);
Arrays.stream(arrayOfLong).limit(10).forEach(i-> System.out.print(i+""));
jjs是一个基于标准Nashorn引擎的命令行工具,可以接受js源码并执行。如有一个func.js文件,可以通过jjs func.js执行js源码。
输入.class文件、目录、jar包,就可以展示包层级和类层级的Java依赖关系。
jdeps org.springframework.core-3.0.5.RELEASE.jar
在java8中去掉了持久区,取而代之的是将原本要放在持久区的类元数据信息、字节码信息及static final的常量,转移到了计算机本地内存中。这样理论上说就不会出现java.lang.OutOfMemoryError: PermGen space的异常。
使用Metaspace(JEP 122)代替持久代(PermGen space)。在JVM参数方面,使用-XX:MetaSpaceSize和-XX:MaxMetaspaceSize代替原来的-XX:PermSize和-XX:MaxPermSize。