JDK8十大新特性

上一篇 <<<十大经典排序算法汇总-动画演示
下一篇 >>>Java集合类图总览


1.Lambda表达式

Lambda 左边(参数)->右边(主体内容)
优点:代码简单、可能代表未来的编程趋势。
缺点:不容易调试,若其他程序员没有学过 lambda 表达式,代码不容易让其他语言的程序员看懂。

new Thread(()->{System.out.println(Thread.currentThread().getName()+"线程启动");}).start();
list.forEach(System.out::println);

2.Stream函数式操作流元素集合

使用Stream API对集合数据进行操作,就类似于使用sql执行的数据库查询。也可以使用Stream API来并行执行操作。

  • (1)创建流的方式
/**实体对象的集合,可以用Stream.of和Arrays.stream方法实现*/
Integer[] integers = {1,2,3,4};
Stream<Integer> integers1 = Stream.of(integers);
integers1.forEach(System.out::println);
System.out.println("---------------------");
Stream<Integer> stream = Arrays.stream(integers);
stream.forEach(System.out::println);
System.out.println("---------------------");

/** 自身就是Collection集合的,可以直接通过自身的stream方法,如:Set,List,SortedSet 等 */
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
stream = list.stream();
stream.forEach(System.out::println);
System.out.println("---------------------");

Map map = new HashMap();
map.put("1","1");
map.put("2","2");
map.put("3","3");
map.put("4","4");
Set set = map.entrySet();
Stream stream1 = set.stream();
stream1.forEach(System.out::println);
System.out.println("---------------------");
/** Stream的静态generate方法,创建无限流--不加limit会出现无限循环*/
Stream<Double> generate = Stream.generate(() -> Math.random());
generate.limit(10).forEach(d -> System.out.println(d));
  • (2)中间操作
 List<User> userList = new ArrayList<>();
 userList.add(new User("张三",18));
 userList.add(new User("李四",19));
 userList.add(new User("王五",18));
 userList.add(new User("王麻子",20));
 userList.add(new User("张三",18));
 /** 筛选与切片 */
 //filter-过滤年龄大于18岁的用户
userList.stream().filter(user -> user.getAge() > 18).forEach(System.out::println);
 System.out.println("---------------------");
 //limit-截断流 按倒序排列获取最近两个
 userList.stream().sorted(((o1, o2) -> o2.getAge()-o1.getAge())).limit(2).forEach(System.out::println);
 System.out.println("---------------------");
 //skip-跳过元素
 userList.stream().skip(2).forEach(System.out::println);
 System.out.println("---------------------");
 //distinct--去重--需要重写hashcode和equals方法
 userList.stream().distinct().forEach(System.out::println);

 System.out.println("---------------------");
 /** 映射 */
 //map——将元素转换成其他形式或提取信息---提取user中的年龄去重然后转为list集合
 List<Integer> collect = userList.stream().map(user -> user.getAge()).distinct().collect(Collectors.toList());
 collect.forEach(System.out::println);
 System.out.println("---------------------");
 //flatMap-把子元素中的流合并为一个全新的流,也就是扁平化处理
 List<List<User>> listList = new ArrayList<>();
 listList.add(userList);
 listList.add(userList);
 Stream<User> userStream = listList.stream().flatMap(users -> users.stream());
 userStream.forEach(System.out::println);
  • (3)终端操作
//anyMatch——对姓名年龄等进行匹配,检查是否至少匹配一个元素
boolean flg = userList.stream().anyMatch(user -> user.getName().indexOf("张") >= 0);
System.out.println(flg);
System.out.println("---------------------");
//max--返回结果中最大值的数据
Optional<User> max = userList.stream().max((o1, o2) -> o1.getAge() - o2.getAge());
System.out.println(max.get());
System.out.println("---------------------");
//归约reduce--计算年纪总数
Optional<Integer> reduce = userList.stream().map(user -> user.getAge()).reduce((user, user2) -> user + user2);
System.out.println(reduce.get());
System.out.println("---------------------");
//collect() 将流转换成其他形式
//求出大于18岁用户的集合
List<User> collect = userList.stream().filter(user -> user.getAge() > 18).collect(Collectors.toList());
collect.forEach(System.out::println);
System.out.println("---------------------");
//每个用户统计了多少次
Map<User, Long> collect1 = userList.stream().collect(Collectors.groupingBy(user -> user, Collectors.counting()));
collect1.entrySet().forEach(System.out::println);
System.out.println("---------------------");
//查询集合中是否有重复的值
List<Map.Entry<User, Long>> collect2 = collect1.entrySet().stream().filter(userLongEntry -> userLongEntry.getValue() > 1).collect(Collectors.toList());
collect2.forEach(System.out::println);
  • (4)实战
//A学生有好友 B,C。
//B学生有好友A,C,D,E,F
//C学生有好友 A,B,D,F
//求找出A学生的 可能认识的人(不是A同学的朋友,但是与A同学有2或以上个相同的好友)
Student studentA = new Student("A", new String[]{"B", "C"});
Student studentB = new Student("B", new String[]{"A", "C", "D", "E", "F"});
Student studentC = new Student("C", new String[]{"A", "B", "D", "F"});
List<Student> students = new ArrayList<>();
students.add(studentA);
students.add(studentB);
students.add(studentC);

//1、获取当前A同学的朋友["B","C"]
Stream<String[]> a = students.stream().filter(student -> student.getName().equals("A")).map(student -> student.getFriend());
List<String[]> collect = a.collect(Collectors.toList());
Stream<String> stringStream = collect.stream().flatMap(strings -> Stream.of(strings));
List<String> friendA = stringStream.collect(Collectors.toList());

//2、获取A同学朋友的朋友["A","C","D","E","F"],["A","B","D","F"]
Stream<Student> studentStream = students.stream().filter(student -> friendA.stream().anyMatch(s -> s.equals(student.getName())));
Stream<String[]> stream = studentStream.map(student -> student.getFriend());
List<String[]> collect1 = stream.collect(Collectors.toList());

//3、将上述集合铺平["A","C","D","E","F","A","B","D","F"]
Stream<String> stringStream1 = collect1.stream().flatMap(strings -> Stream.of(strings));
List<String> collect2 = stringStream1.collect(Collectors.toList());

//4、剔除A自身和A的朋友["D","E","F","D","F"]
Stream<String> a1 = collect2.stream().filter(s -> !(s.equals("A") || friendA.stream().anyMatch(s1 -> s1.equals(s))));
List<String> collect3 = a1.collect(Collectors.toList());
System.out.println(collect3);

//5、计算重复的值及重复的次数
Map<String, Long> collect4 = collect3.stream().collect(Collectors.groupingBy(o -> o, Collectors.counting()));
System.out.println(collect4);

3.接口新增:默认方法与静态方法

函数式接口(注解:@FunctionalInterface),可以通过Lambda表达式来创建该接口的对象。
它只包含一个自定义的抽象方法的接口, 还可以是Object类的equals抽象方法,还可以default、static修饰的自带方法体,如果实现多个相同default方法的接口,则default方法必须重写。

函数式接口 参数类型 返回类型 用途
java.util.function.Consumer<T> T void 对类型为T的对象应用操作,包含方法void accept(T t);【消费型】
java.util.function.Supplier<T> T 返回类型为T的对象,包含方法 T get(); 【供给型】
java.util.function.Function<T,R> T R 参数类型T,返回类型R,包含方法 R apply(T t); 【函数型】
java.util.function.Predicate<T> T boolean 参数类型T,返回类型boolean,包含方法 boolean test(T t); 【断言型】
    /**
     * 接口新增:默认方法与静态方法
     *  default 接口默认实现方法是为了让集合类默认实现这些函数式处理,而不用修改现有代码
     *  (List继承于Iterable<T>,接口默认方法不必须实现default forEach方法)
     */
    @Test
    public void testDefaultFunctionInterface(){
        //可以直接使用接口名.静态方法来访问接口中的静态方法
        JDK8Interface1.staticMethod();
        //接口中的默认方法必须通过它的实现类来调用
        new JDK8InterfaceImpl1().defaultMethod();
        //多实现类,默认方法重名时必须复写
        new JDK8InterfaceImpl2().defaultMethod();
    }
    //@FunctionalInterface
public interface JDK8Interface1 {

    //1.接口中可以定义静态方法了
    public static void staticMethod(){
        System.out.println("接口中的静态方法");
    }
    
    //2.使用default之后就可以定义普通方法的方法体了
    public default void defaultMethod(){
        System.out.println("接口中的默认方法");
    }

//    public abstract void add();
}

public interface JDK8Interface2 {

    //接口中可以定义静态方法了
    public static void staticMethod(){
        System.out.println("接口中的静态方法");
    }
    //使用default之后就可以定义普通方法的方法体了
    public default void defaultMethod(){
        System.out.println("接口中的默认方法");
    }
}
    public class JDK8InterfaceImpl1 implements JDK8Interface1 {
        //实现接口后,因为默认方法不是抽象方法,重写/不重写都成!
//        @Override
//        public void defaultMethod(){
//            System.out.println("接口中的默认方法");
//        }
    }
    
    public class JDK8InterfaceImpl2 implements JDK8Interface1,JDK8Interface2 {
        //实现接口后,默认方法名相同,必须复写默认方法
        @Override
        public void defaultMethod() {
            //接口的
            JDK8Interface1.super.defaultMethod();
            System.out.println("实现类复写重名默认方法!!!!");
        }
    }

4.方法引用,与Lambda表达式联合使用

其实是lambda的简写,中间函数式接口只起到上下文作用,可直接省去,直接写函数式接口的具体实现,使用方法引用的方式

public void testMethodReference(){
    //构造器引用。语法是Class::new,或者更一般的Class< T >::new,要求构造器方法是没有参数;
    final Car car = Car.create( Car::new );
    final List< Car > cars = Arrays.asList( car );
    //静态方法引用。语法是Class::static_method,要求接受一个Class类型的参数;
    cars.forEach( Car::collide );
    //任意对象的方法引用。它的语法是Class::method。无参,所有元素调用;
    cars.forEach( Car::repair );
    //特定对象的方法引用,它的语法是instance::method。有参,在某个对象上调用方法,将列表元素作为参数传入;
    final Car police = Car.create( Car::new );
    cars.forEach( police::follow );
}

public static class Car {
    public static Car create( final Supplier< Car > supplier ) {
        System.out.println("构造函数被初始化");
        return supplier.get();
    }              
         
    public static void collide( final Car car ) {
        System.out.println( "静态方法引用 " + car.toString() );
    }
         
    public void repair() {   
        System.out.println( "任意对象的方法引用 " + this.toString() );
    }
    
    public void follow( final Car car ) {
        System.out.println( "特定对象的方法引用 " + car.toString() );
    }
}

5.引入重复注解

允许在同一申明类型(类,属性,或方法)前多次使用同一个类型注解。

@Filters({@Filter(  value="filter1",value2="111" ),@Filter(  value="filter2", value2="222")})
--写法改为了-->
@Filter( value="filter1",value2="111" )
@Filter( value="filter2", value2="222")

6.类型注解

ElementType 枚举增加了TYPE_PARAMETER、TYPE_USE两个枚举值,从而可以使用 @Target(ElementType_TYPE_USE) 修饰注解定义,这种注解被称为类型注解,可以用在任何使用到类型的地方。

TYPE_PARAMETER:表示该注解能写在类型参数的声明语句中。 类型参数声明如: <T>、<T extends Person>

TYPE_USE:表示注解可以再任何用到类型的地方使用,比如允许在如下位置使用:
a.创建对象(用 new 关键字创建)
b.类型转换
c.使用 implements 实现接口
d.使用 throws 声明抛出异常

7.最新的Date/Time API (JSR 310)

//1.Clock
final Clock clock = Clock.systemUTC();
System.out.println( clock.instant() );//2020-12-24T07:32:56.132Z
System.out.println( clock.millis() );//1608795176247

//2. ISO-8601格式且无时区信息的日期部分
final LocalDate date = LocalDate.now();
final LocalDate dateFromClock = LocalDate.now( clock );
         
System.out.println( date );//2020-12-24
System.out.println( dateFromClock );//2020-12-24
         
// ISO-8601格式且无时区信息的时间部分
final LocalTime time = LocalTime.now();
final LocalTime timeFromClock = LocalTime.now( clock );
         
System.out.println( time );//15:32:56.257
System.out.println( timeFromClock );//15:32:56.257

// 3.ISO-8601格式无时区信息的日期与时间
final LocalDateTime datetime = LocalDateTime.now();
final LocalDateTime datetimeFromClock = LocalDateTime.now( clock );
         
System.out.println( datetime );//2020-12-24T15:32:56.257
System.out.println( datetimeFromClock );//2020-12-24T15:32:56.257

// 4.特定时区的日期/时间,
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 );//2020-12-24T15:32:56.258+08:00[Asia/Shanghai]
System.out.println( zonedDatetimeFromClock );//2020-12-24T07:32:56.258Z
System.out.println( zonedDatetimeFromZone );2020-12-23T23:32:56.260-08:00[America/Los_Angeles]

//5.在秒与纳秒级别上的一段时间
final LocalDateTime from = LocalDateTime.of( 2014, Month.APRIL, 16, 0, 0, 0 );
final LocalDateTime to = LocalDateTime.of( 2015, Month.APRIL, 16, 23, 59, 59 );
 
final Duration duration = Duration.between( from, to );
System.out.println( "Duration in days: " + duration.toDays() );//365
System.out.println( "Duration in hours: " + duration.toHours() );//8783

8.新增base64加解密API

final String text = "就是要测试加解密!!abjdkhdkuasu!!@@@@";
String encoded = Base64.getEncoder().encodeToString( text.getBytes( StandardCharsets.UTF_8 ) );
System.out.println("加密后="+ encoded );

final String decoded = new String(Base64.getDecoder().decode( encoded ),StandardCharsets.UTF_8 );
System.out.println( "解密后="+decoded );

9.数组并行(parallel)操作

long[] arrayOfLong = new long [ 20000 ];        
//1.给数组随机赋值
Arrays.parallelSetAll( arrayOfLong, 
    index -> ThreadLocalRandom.current().nextInt( 1000000 ) );
//2.打印出前10个元素
Arrays.stream( arrayOfLong ).limit( 10 ).forEach( 
    i -> System.out.print( i + " " ) );
System.out.println();
//3.数组排序
Arrays.parallelSort( arrayOfLong );     
//4.打印排序后的前10个元素
Arrays.stream( arrayOfLong ).limit( 10 ).forEach( 
    i -> System.out.print( i + " " ) );
System.out.println();

10.JVM的PermGen方法区被移除:取代它的是Metaspace(JEP 122)元空间

-XX:MetaspaceSize初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整
-XX:MaxMetaspaceSize最大空间,默认是没有限制
-XX:MinMetaspaceFreeRatio在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
-XX:MaxMetaspaceFreeRatio在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集

相关文章链接:
<<<Java基础-反射机制
<<<Java基础-字节码技术
<<<Java基础-创建对象的方式汇总
<<<Java基础-对象布局
<<<Java基础-对象的引用类型
<<<Class文件分析一个类为啥最多支持65535个接口
<<<为什么重写equals还要重写hashcode方法
<<<如何自定义注解
<<<十大经典排序算法汇总-动画演示

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容