Jdk1.8新特性

2 篇文章 0 订阅

1 接口的默认方法
Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default或static关键字即可,这个特征又叫做扩展方法。

public interface Jdk8Interface {
	
    int interfaceMethod();
	
    default void defaultMethod(){
        System.out.println("DefalutTest defalut method");
    }

    static void staticMethod() {
        System.out.println("DefalutTest static method");
    } 
}

1.1 static

接口里的静态方法,即static修饰的有方法体的方法不能被继承,也不能被实现类调用,只能被自身调用,但是静态变量会被继承。

接口.static方法调用,如:Jdk8Interface.staticMethod();

public class TestDemo {
	public static void main(String[] args) {
		Jdk8Interface.staticMethod();
	}
}

1.2 default

public class TestDemo {
	public static void main(String[] args) {		
		Jdk8InterfaceImp imp = new Jdk8InterfaceImp();
		imp.defaultMethod();
	}
}
default方法可以被子接口继承亦可被其实现类所调用
public interface SubJdk8Interface extends Jdk8Interface {
	
}
public class SubJdk8InterfaceImp implements SubJdk8Interface {
	@Override
	public int interfaceMethod() {
		// TODO Auto-generated method stub
		return 0;
	}
}
public class TestDemo {
	public static void main(String[] args) {
		SubJdk8InterfaceImp imp = new SubJdk8InterfaceImp();
		imp.defaultMethod();
	}
}

default方法被继承时,可以被子接口覆写

public interface SubJdk8Interface extends Jdk8Interface {
	@Override
	public default void defaultMethod() {
		 System.out.println("SubJdk8Interface defalut method");
	}
}

2 Lambda表达式

2.1 Lambda表达式的基础语法:Java8引入了一个新的操作符“->”,该操作符成为箭头操作符或者Lambda操作符,箭头操作符将Lambda表达式拆分成两部分

左侧:Lambda表达式的参数列表
右侧:Lambda表达式中所需执行的功能,即Lambda体。

Java 8 中传统的匿名对象的方式可以被更简洁的语法替代,lambda表达式:

List<String> names = Arrays.asList("Angelia", "Snowdrop", "Lili");
		
Collections.sort(names, new Comparator<String>() {
	@Override
	public int compare(String a, String b) {
		return a.compareTo(b);
	}			
});
		
Collections.sort(names, (String a, String b) -> {
        return a.compareTo(b);
});

//还可以更简洁:左边参数类型省略,根据实际传参确定,右边Lambda体中只有一条语句,return和大括号都可以省略不写。
Collections.sort(names, (a, b)->a.compareTo(b));

3 函数式接口
所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法。@FunctionalInterface注解接口,如果接口不满足条件,会报错。

/**
 * 声明函数式接口,接口中声明抽象方法,public String getName(String str);
 * 声明类TestDemo,类中编写方法使用接口作为参数,讲一个字符串转换成大写,并作为方法的返回值。
 */
public class TestDemo {
    public static void main(String[] args) {
        TestDemo test = new TestDemo();
        String str = test.getName("Hello Angelia", x->x.toUpperCase());
        System.out.println(str);
    }
    
    public String getName(String str, MyInterface my){
        return my.getName(str);
    }
    
    @FunctionalInterface
    public interface MyInterface{
        public String getName(String str);
    }
}
/*Java8中的核心函数式接口
Consumer<T> :消费型接口
    void accept(T t);

Supplier<T> :供给型接口
    T get();

Function<T,R> :函数型接口
    R apply(T t);

Predicate<T> :断言型接口
    boolean test(T t);*/ 

4 方法与构造函数引用

Java 8 允许关键字 :: 来传递方法或者构造函数引用。

4.1 方法引用
若Lambda体中的内容有方法已经实现了,我们可以使用“方法引用”。主要语法:
对象::实例方法名
类::静态方法名
类::实例方法名

public class TestDemo {
    public static void main(String[] args) {
	    /*TestDemo test = new TestDemo();
	    String str = test.getName("Hello Angelia", x->x.toUpperCase());
	    System.out.println(str);*/
	    
	    MyInterface my = x->x.toUpperCase();
	    String str = my.getName("Hello Angelia");
	    System.out.println(str);
	    
	    MyInterface my2 = String::toLowerCase;
	    String str2 = my2.getName("Hello Angelia");
	    System.out.println(str2);
	}
    public String getName(String str, MyInterface my){
        return my.getName(str);
    }
	
    @FunctionalInterface
    public interface MyInterface{
        public String getName(String str);
    }
}
注意:

①Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型一致。
②若Lambda参数列表中的第一参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method进行调用。

4.2 构造器引用

格式:ClassName::new

public class PersonDemo {
	public static void main(String[] args) {
		/**
		 * 3.这里我们使用构造函数引用来将他们关联起来,而不是实现一个完整的工厂:
		 */
		PersonFactory<Person> personFactory = Person::new;
		Person person = personFactory.create("Angelia", "Zheng");
		System.out.println(person);
	}
}
/**
 * 1.首先定义一个包含多个构造函数的简单类
 */
class Person {
    String firstName;
    String lastName;

    Person() {}

    Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Override
    public String toString() {
	return "Person [firstName=" + firstName + ", lastName=" + lastName + "]";
    }
}
/**
 * 2.接下来我们指定一个用来创建Person对象的对象工厂接口
 */
interface PersonFactory<P extends Person> {
    P create(String firstName, String lastName);
}
注意:需要引用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致。

5 Annotation 注解:支持多重注解

Java 8允许我们把同一个类型的注解使用多次,只需要给该注解标注一下@Repeatable即可。

public class AnnotationDemo {
    public static void main(String[] args) {
        MyAnnotation myAnnotation = AnnotationTest1.class.getAnnotation(MyAnnotation.class);

        System.out.println(myAnnotation); //null

        MyAnnotations myAnnotations1 = AnnotationTest1.class.getAnnotation(MyAnnotations.class);
        System.out.println(myAnnotations1.value().length); //2

        MyAnnotation[] myAnnotations2 = AnnotationTest1.class.getAnnotationsByType(MyAnnotation.class);
        System.out.println(myAnnotations2.length); //2
    }
}

/**
 * 将使用反射技术来解析此注解。注解的RetentionPolicy应该设置为RUNTIME。 否则注解信息在执行过程中将不可用。
 */
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotations {
    MyAnnotation[] value();
}

@Repeatable(MyAnnotations.class)
@interface MyAnnotation {
    String value();
}

/** 老方法:使用包装类当容器来存多个注解 */
@MyAnnotations({@MyAnnotation("MyAnnotation1"), @MyAnnotation("MyAnnotation2")})
class AnnotationTest1{
}

/** 新方法:使用多重注解 */
@MyAnnotation("MyAnnotation1")
@MyAnnotation("MyAnnotation2")
class AnnotationTest2{
}

6 新的日期时间 API

Java 8 在包java.time下包含了一组全新的时间日期API。新的日期API和开源的Joda-Time库差不多,但又不完全一样。其中比较常用的类有Clock、LocaleDate、LocalTime、LocaleDateTime、ZonedDateTime、Timezones等。

Clock 时钟
Clock类提供了访问当前日期和时间的方法,Clock是时区敏感的,可以用来取代 System.currentTimeMillis() 来获取当前的微秒数。某一个特定的时间点也可以使用Instant类来表示,Instant类也可以用来创建老的java.util.Date对象。
Clock clock = Clock.systemDefaultZone();
long mills = clock.millis();

Instant instant = clock.instant();
Date legacyDate = Date.from(instant);

LocalDate

本地日期LocalDate 表示了一个确切的日期,比如 2018-05-10。该对象值是不可变的,用起来和LocalTime基本一致。下面的例子展示了如何给Date对象加减天/月/年。另外要注意的是这些对象是不可变的,操作返回的总是一个新实例。

LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS);
LocalDate yesterday = tomorrow.minusDays(2);

LocalDate independenceDay = LocalDate.of(2018, Month.MAY, 10);
DayOfWeek dayOfWeek = independenceDay.getDayOfWeek();

LocalTime

LocalTime 定义了一个没有时区信息的时间,例如 晚上10点,或者 15:30:15。下面的例子使用前面代码创建的时区创建了两个时间。之后比较时间并以小时和分钟为单位计算两个时间的时间差:

LocalTime now1 = LocalTime.now(); //15:30:15
LocalTime now2 = LocalTime.now(ZoneId.of("Europe/Berlin")); //10:05:36

long hoursBetween = ChronoUnit.HOURS.between(now1, now2);
long minutesBetween = ChronoUnit.MINUTES.between(now1, now2);

LocalDateTime 本地日期时间

LocalDateTime 同时表示了时间和日期,相当于前两节内容合并到一个对象上了。LocalDateTime和LocalTime还有LocalDate一样,都是不可变的。LocalDateTime提供了一些能访问具体字段的方法。
LocalDateTime dateTime = LocalDateTime.of(2018, Month.MAY, 10, 16, 9, 59);

DayOfWeek dayOfWeek = dateTime.getDayOfWeek();
System.out.println(dayOfWeek); //THURSDAY

Month month = dateTime.getMonth();
System.out.println(month); //MAY

long minuteOfDay = dateTime.getLong(ChronoField.MINUTE_OF_DAY);
System.out.println(minuteOfDay); //969

Timezones 时区

在新API中时区使用ZoneId来表示。时区可以很方便的使用静态方法of来获取到。 时区定义了到UTS时间的时间差,在Instant时间点对象到本地日期对象之间转换的时候是极其重要的。

System.out.println(ZoneId.getAvailableZoneIds());

ZoneId zone1 = ZoneId.of("America/Cuiaba");
ZoneId zone2 = ZoneId.of("Etc/GMT+9");
System.out.println(zone1.getRules());
System.out.println(zone2.getRules());
7 Stream
Stream API是把真正的函数式编程风格引入到Java中。它其实是一连串支持连续、并行聚集操作的元素。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AngeliaZheng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值