#推荐、参考资料 参考资料:Java 8 简明教程html
中文API:中文APIjava
JAVA8 十大新特性详解:JAVA8 十大新特性详解git
Java8的新特性以及用法简介:Java8的新特性以及用法简介github
#扯淡面试
java8相对之前的版本应该说是一个重要的版本:看过一个笑话,大概是--》 今天CTO推荐了一个10年编程经验的大牛来公司面试。正好主程在开会,因而叫了一个应届生去面试,本想就走个流程,可是没想到,最后这个大牛被拒了。主程问这位应届生,怎么回事。应届生不屑的说,一问三不知,Lambda,Stream都没据说过。spring
#新特性编程
##一、Lambda表达式和函数式接口api
由逗号分隔的参数列表、->符号和语句块组成并发
public static void main(String[] args) { List<String> list = Arrays.asList("3", "1", "2"); //循环输出 list.forEach(e -> System.out.println(e)); //排序 list.sort((e1, e2) -> { int r = e1.compareTo(e2); return r; }); list.forEach(e -> System.out.println(e)); }
函数接口指的是只有一个函数的接口,这样的接口能够隐式转换为Lambda表达式。java.lang.Runnable和java.util.concurrent.Callable是函数式接口的最佳例子。ide
显式说明某个接口是函数式接口,Java 8 提供了一个特殊的注解@FunctionalInterface(Java 库中的全部相关接口都已经带有这个注解了),举个简单的函数式接口的定义:
@FunctionalInterface public interface FunctionalDefaultMethods { void method(); default void defaultMethod() { } }
默认方法和静态方法不会破坏函数式接口的定义,所以以下的代码是合法的。
@FunctionalInterface public interface FunctionalDefaultMethods { void method(); default void defaultMethod() { } }
##二、接口的默认方法、静态方法
Java 8使用两个新概念扩展了接口的含义:默认方法和静态方法。
默认方法:往现存接口中添加新的方法,即不强制那些实现了该接口的类也同时实现这个新加的方法。 默认方法和抽象方法之间的区别在于抽象方法须要实现,而默认方法不须要。接口提供的默认方法会被接口的实现类继承或者覆写。使用关键字default定义 如
private interface Defaulable { // Interfaces now allow default methods, the implementer may or // may not implement (override) them. default String notRequired() { return "Default implementation"; } }
静态方法:使用关键字static 定义 如
private interface DefaulableFactory { static Defaulable create( Supplier< Defaulable > supplier ) { return supplier.get(); } }
##三、方法引用
在学习lambda表达式以后,咱们一般使用lambda表达式来建立匿名方法。然而,有时候咱们仅仅是调用了一个已存在的方法。以下:
Arrays.sort(stringsArray,(s1,s2)->s1.compareToIgnoreCase(s2));
在Java8中,咱们能够直接经过方法引用来简写lambda表达式中已经存在的方法。
Arrays.sort(stringsArray, String::compareToIgnoreCase);
这种特性就叫作方法引用(Method Reference)。
方法引用的形式 方法引用的标准形式是:类名::方法名。(注意:只须要写方法名,不须要写括号)
有如下四种形式的方法引用:
类型 | 示例 |
---|---|
引用静态方法 | ContainingClass::staticMethodName |
引用某个对象的实例方法 | containingObject::instanceMethodName |
引用某个类型的任意对象的实例方法 | ContainingType::methodName |
引用构造方法 | ClassName::new |
举个栗子---
public class User { public static User create(Supplier<User> supplier) { System.out.println("create "); return supplier.get(); } public static String name(User u) { System.out.println("name "); return "呵呵"; } public int age(User u) { System.out.println("age "); return 18; } } public class MethodTest { public static void main(String[] args) { //构造器的引用 User user = User.create(User::new); List<User> users = Arrays.asList(user); //静态方法引用 users.forEach(User::name); //对象方法的引用 users.forEach(user::age); String[] stringsArray = {"Hello", "World"}; //使用lambda表达式和类型对象的实例方法 Arrays.sort(stringsArray, (s1, s2) -> s1.compareToIgnoreCase(s2)); //使用方法引用 //引用的是类型对象的实例方法 Arrays.sort(stringsArray, String::compareToIgnoreCase); Arrays.asList(stringsArray).stream().forEach(x -> System.out.println(x)); //引用的是类型对象的实例方法 Arrays.asList(stringsArray).stream().forEach(System.out::println); } }
##四、重复注解和新的target
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类使用@Repeatable(Filters.class)注解修饰,而Filters是存放Filter注解的容器,编译器尽可能对开发者屏蔽这些细节。这样,Filterable接口能够用两个Filter注解注释(这里并无提到任何关于Filters的信息)。 另外,反射API提供了一个新的方法:getAnnotationsByType(),能够返回某个类型的重复注解,例如Filterable.class.getAnnoation(Filters.class)将返回两个Filter实例,输出到控制台的内容以下所示: filter1 filter2
###新的target 另外Java 8的注解还增长到两种新的target上了:
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
@interface MyAnnotation {}
##五、更好的类型推荐
--好像没什么好说的。感受要去体会,呵呵。
##六、Optional Optional仅仅是一个容易:存放T类型的值或者null。它提供了一些有用的接口来避免显式的null检查
public class OptionalTest { public static void main(String[] args) { Optional< String > fullName = Optional.ofNullable( null ); //若是Optional实例持有一个非空值,则isPresent()方法返回true,不然返回false; System.out.println( "Full Name is set? " + fullName.isPresent() ); //orElseGet()方法,Optional实例持有null,则能够接受一个lambda表达式生成的默认值 System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) ); //map()方法能够将现有的Opetional实例的值转换成新的值; System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) ); //orElse()方法与orElseGet()方法相似,可是在持有null的时候返回传入的默认值 } } 输出 Full Name is set? false Full Name: [none] Hey Stranger!
#七、Streams
public class StreamEntity { private String name; private int age; public StreamEntity(String name, int age) { this.name = name; this.age = age; } ------------------------ public class StreamTest { public static void main(String[] args) { List<StreamEntity> list = Arrays.asList(new StreamEntity("张三", 19), new StreamEntity("李四", 20), new StreamEntity ("王五", 18), new StreamEntity("呵呵", 19)); int sum = list.stream().filter(u -> u.getAge() > 18).mapToInt(u -> u.getAge()).sum(); System.out.println(sum); } } 输出 58
list集合被转换成steam表示;其次,在steam上的filter操做会过滤掉全部age大于18 的;第三,mapToInt操做基于每一个task实例的getAge方法将list流转换成Integer集合;最后,经过sum方法计算总和,得出最后的结果。
** Steam之上的操做可分为中间操做和晚期操做。 中间操做会返回一个新的steam——执行一个中间操做(例如filter)并不会执行实际的过滤操做,而是建立一个新的steam,并将原steam中符合条件的元素放入新建立的steam。 晚期操做(例如forEach或者sum),会遍历steam并得出结果或者附带结果;在执行晚期操做以后,steam处理线已经处理完毕,就不能使用了。在几乎全部状况下,晚期操做都是马上对steam进行遍历。 steam的另外一个价值是创造性地支持并行处理(parallel processing) **
//parallel() 并行流 public class StreamTest { public static void main(String[] args) { List<StreamEntity> list = Arrays.asList(new StreamEntity("张三", 19), new StreamEntity("李四", 20), new StreamEntity ("王五", 18), new StreamEntity("呵呵", 19)); int sum = list.stream().parallel().filter(u -> u.getAge() >= 19).mapToInt(u -> u.getAge()).reduce(0,(a,b)->a+b); int sum1 = list.stream().parallel().filter(u -> u.getAge() >= 19).mapToInt(u -> u.getAge()).reduce(0, Integer::sum); System.out.println(sum); System.out.println(sum1); } } //reduce 万能的,,,后面博客介绍 输出 58 58
###Stream的分组
Map<Integer, List< StreamEntity >> m = list.stream().parallel().collect(Collectors.groupingBy(streamEntity -> streamEntity.getAge())); m.forEach((k, v) -> System.out.println("key:value = " + k + ":" + v) ); 输出 key:value = 18:[com.slife.java8.StreamEntity@71c7db30] key:value = 19:[com.slife.java8.StreamEntity@19bb089b, com.slife.java8.StreamEntity@4563e9ab] key:value = 20:[com.slife.java8.StreamEntity@11531931]
##Date/Time API
使用用Clock替代System.currentTimeMillis()和TimeZone.getDefault()。
final Clock clock = Clock.systemUTC(); System.out.println(clock.instant()); System.out.println(clock.millis()); 输出 2017-10-23T06:20:22.437Z 1508739622508 `` ###LocalDate和LocalTime、LocalDateTime类
final LocalDate date = LocalDate.now(); final LocalDate dateFromClock = LocalDate.now( clock );
System.out.println( date ); System.out.println( dateFromClock );
// Get the local date and local time final LocalTime time = LocalTime.now(); final LocalTime timeFromClock = LocalTime.now( clock );
System.out.println( time ); System.out.println( timeFromClock );
须要特定时区的data/time信息,则可使用**ZoneDateTime**
final ZonedDateTime zonedDatetime = ZonedDateTime.now(); final ZonedDateTime zonedDatetimeFromClock = ZonedDateTime.now( clock ); final ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now( ZoneId.of( "America/Los_Angeles" ) );
System.out.println( zonedDatetime ); System.out.println( zonedDatetimeFromClock ); System.out.println( zonedDatetimeFromZone );
###**Duration**类,它持有的时间精确到秒和纳秒 计算两个日期的秒和天数
// Get duration between two dates final LocalDateTime from = LocalDateTime.of( 2016, Month.APRIL, 16, 0, 0, 0 ); final LocalDateTime to = LocalDateTime.of( 2017, Month.APRIL, 16, 23, 59, 59 );
final Duration duration = Duration.between( from, to ); System.out.println( "Duration in days: " + duration.toDays() ); System.out.println( "Duration in hours: " + duration.toHours() );
#Nashorn JavaScript引擎 Nashorn JavaScript引擎,使得咱们能够在JVM上开发和运行JS应用。,容许Java和JavaScript交互使用 #Base64 java8提供了Base64的api #并行、并发特性 parallelXXX , DoubleAccumulator DoubleAdder LongAccumulator LongAdder 之后的博客中详细介绍。 #VM的新特性 使用Metaspace(JEP 122)代替持久代(PermGen space)。在JVM参数方面,使用-XX:MetaSpaceSize和-XX:MaxMetaspaceSize代替原来的-XX:PermSize和-XX:MaxPermSize。 个人官网  个人官网<http://guan2ye.com> 个人CSDN地址<http://blog.csdn.net/chenjianandiyi> 个人简书地址<http://www.jianshu.com/u/9b5d1921ce34> 个人github<https://github.com/javanan> 个人码云地址<https://gitee.com/jamen/> [阿里云优惠券https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=vf2b5zld&utm_source=vf2b5zld](https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=vf2b5zld&utm_source=vf2b5zld)