文章目录
- Java语言新特性
- 1.Lambda表达式和函数式接口
- 2.接口的默认方法和静态方法
- 3.方法引用
- 4.重复注解
- 5.更好的类型推断
- 6.拓宽注解的应用场景
- Java编译器新特性
- 参数名称
- JVM的新特性
java8 新特性精心整理(全)。
Java语言新特性
1.Lambda表达式和函数式接口
比如:
@FunctionalInterface
public interface Comparator<T> {
...
}
# main
Integer[] arr=new Integer[4];
Arrays.sort(arr,(o1,o2)->o2-o1);//Comparator
又比如:
# main
Arrays.asList(1,2,3,4).forEach(System.out::println);//Consumer
不做赘述,参考探索Java8——Lambda表达式。
2.接口的默认方法和静态方法
这个之前也介绍过了,也就是jdk8之后接口能够使用default和static方法:
interface Defaulable{
default String defaultMethod() {
return "Default implementation";
}
}
interface DefaulableFactory{
static Defaulable staticMethod(Supplier<Defaulable> supplier){
return supplier.get();
}
}
class Main implements Defaulable{
public static void main(String[] args) {
Defaulable defaulable =DefaulableFactory.staticMethod(Main::new);
System.out.println(defaulable.defaultMethod());
}
}
当然也可以Override重写:
class Main implements Defaulable{
@Override
public String defaultMethod() {
return null;
}
...
}
3.方法引用
java8方法引用有四种形式:
- 构造器引用 :
Class :: new
- 静态方法引用 :
Class :: staticMethodName
- 类的任意对象的实例方法引用:
Class :: instanceMethodName
- 特定对象的实例方法引用 :
object :: instanceMethodName
第一种方法引用的类型是构造器引用,语法是Class::new
,或者更一般的形式:Class<T>::new
。注意:这个构造器没有参数。
class Main {
public static Main mainFactory(Supplier<Main> supplier){
return supplier.get();
}
public static void main(String[] args) {
Supplier<Main> supplier=Main::new;
//等价于 Supplier<Main> supplier=()->new Main();
Main m=Main.mainFactory(supplier);
}
}
第二种方法引用的类型是静态或者普通方法引用,语法是Class::staticMethodName
。
public class Test {
public static void main(String[] args) {
//lambda表达式使用:
Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(s -> Test.println(s));
//静态方法引用:
Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(Test::println);
}
public static void println(String s) {
System.out.println(s);
}
}
第三种方法引用的类型是某个类的成员方法的引用,语法是Class::instanceMethodName
,
# main
Arrays.sort(strs, String::compareToIgnoreCase);//Comparator
@FunctionalInterface
public interface Comparator<T> {
//compare是两个参数,也就是比实际调用的compareToIgnoreCase()多出一个参数。
//第一个参数T o1传的是对象,作用另一个例子会讲到。
int compare(T o1, T o2);
}
# 而String的compareToIgnoreCase()函数如下:
public int compareToIgnoreCase(String str) {
//这里实际上使用的是第二个参数T o2
return CASE_INSENSITIVE_ORDER.compare(this, str);
}
换个例子能更好的理解:
public class Student
{
private String name;
private Integer score;
public void setNameAndScore(String name, Integer score)
{
this.name = name;
this.score = score;
System.out.println("Student "+ name +"'s score is " + score);
}
public static void main(String[] args)
{
/*lambda表达式的用法:
TestInterface testInterface = (student, name, score) -> student.setNameAndScore(name, score);*/
//类的任意对象的实例方法引用的用法:
TestInterface testInterface = Student::setNameAndScore;
testInterface.set(new Student(), "DoubleBin", 100);
}
@FunctionalInterface
interface TestInterface
{
// 注意:入参比Student类的setNameAndScore方法多1个Student对象,除第一个外其它入参类型一致
public void set(Student d, String name, Integer score);
}
}
第四种方法引用的类型是某个实例对象的成员方法的引用,语法是object :: instanceMethodName
。
public class Test
{
public static void main(String[] args)
{
Test test = new Test();
// lambda表达式使用:
Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(s -> test.println(s));
// 特定对象的实例方法引用:
Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(test::println);
}
public void println(String s)
{
System.out.println(s);
}
}
第四种方法其实和第三种差不多,只不多第三个多出了一个参数用来传入了object罢了。
4.重复注解
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() );
}
}
}
-
@Repeatable( Filters.class )
为什么要有后面一段Filters.class
?
Filters是保存Filter注解的容器。(可以理解为数组存放了元素)
5.更好的类型推断
Java 8编译器在类型推断方面有很大的提升,在很多场景下编译器可以推导出某个参数的数据类型,从而使得代码更为简洁。例子代码如下:
public class Value< T > {
public static<T> T defaultValue() {
return null;
}
public T getOrDefault( T value, T defaultValue ) {
return ( value != null ) ? value : defaultValue;
}
public static void main(String[] args) {
final Value< String > value = new Value<>();
String s=value.getOrDefault( "22", Value.defaultValue() );
String s2=value.getOrDefault(null,Value.defaultValue());
}
}
参数Value.defaultValue()的类型由编译器推导得出,不需要显式指明。在Java 7中这段代码会有编译错误,除非使用Value.<String>defaultValue()
。
6.拓宽注解的应用场景
之前文章介绍过@Target注解,在JAVA8中,@Target多了这两个类型:
/**
* Type parameter declaration
*
* @since 1.8
*/
/** 用来标注类型参数 */
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
/** 能标注任何类型名称 */
TYPE_USE
}
public class TestTypeUse {
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TypeUseAnnotation {
}
public static @TypeUseAnnotation class TypeUseClass<@TypeUseAnnotation T> extends @TypeUseAnnotation Object {
public void foo(@TypeUseAnnotation T t) throws @TypeUseAnnotation Exception {
}
}
// 如下注解的使用都是合法的
@SuppressWarnings({ "rawtypes", "unused", "resource" })
public static void main(String[] args) throws Exception {
TypeUseClass<@TypeUseAnnotation String> typeUseClass = new @TypeUseAnnotation TypeUseClass<>();
typeUseClass.foo("");
List<@TypeUseAnnotation Comparable> list1 = new ArrayList<>();
List<? extends Comparable> list2 = new ArrayList<@TypeUseAnnotation Comparable>();
@TypeUseAnnotation String text = (@TypeUseAnnotation String)new Object();
java.util. @TypeUseAnnotation Scanner console = new java.util.@TypeUseAnnotation Scanner(System.in);
}
}
Java编译器新特性
参数名称
为了在运行时获得Java程序中方法的参数名称,老一辈的Java程序员必须使用不同方法,例如Paranamer liberary。Java 8终于将这个特性规范化,在语言层面(使用反射API和Parameter.getName()方法)和字节码层面(使用新的javac编译器以及-parameters参数)提供支持。
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
public class ParameterNames {
public static void main(String[] args) throws Exception {
Method method = ParameterNames.class.getMethod( "main", String[].class );
for( final Parameter parameter: method.getParameters() ) {
System.out.println( "Parameter: " + parameter.getName() );
}
}
}
JVM的新特性
使用Metaspace(JEP 122)代替持久代(PermGen space)。在JVM参数方面,使用-XX:MetaSpaceSize和-XX:MaxMetaspaceSize代替原来的-XX:PermSize和-XX:MaxPermSize。