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 integers1 = Stream.of(integers);
integers1.forEach(System.out::println);
System.out.println("---------------------");
Stream stream = Arrays.stream(integers);
stream.forEach(System.out::println);
System.out.println("---------------------");

/** 自身就是Collection集合的,可以直接通过自身的stream方法,如:Set,List,SortedSet 等 */
List 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 generate = Stream.generate(() -> Math.random());
generate.limit(10).forEach(d -> System.out.println(d));
  • (2)中间操作
 List 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 collect = userList.stream().map(user -> user.getAge()).distinct().collect(Collectors.toList());
 collect.forEach(System.out::println);
 System.out.println("---------------------");
 //flatMap-把子元素中的流合并为一个全新的流,也就是扁平化处理
 List> listList = new ArrayList<>();
 listList.add(userList);
 listList.add(userList);
 Stream 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 max = userList.stream().max((o1, o2) -> o1.getAge() - o2.getAge());
System.out.println(max.get());
System.out.println("---------------------");
//归约reduce--计算年纪总数
Optional reduce = userList.stream().map(user -> user.getAge()).reduce((user, user2) -> user + user2);
System.out.println(reduce.get());
System.out.println("---------------------");
//collect() 将流转换成其他形式
//求出大于18岁用户的集合
List collect = userList.stream().filter(user -> user.getAge() > 18).collect(Collectors.toList());
collect.forEach(System.out::println);
System.out.println("---------------------");
//每个用户统计了多少次
Map collect1 = userList.stream().collect(Collectors.groupingBy(user -> user, Collectors.counting()));
collect1.entrySet().forEach(System.out::println);
System.out.println("---------------------");
//查询集合中是否有重复的值
List> 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 students = new ArrayList<>();
students.add(studentA);
students.add(studentB);
students.add(studentC);

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

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

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

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

//5、计算重复的值及重复的次数
Map 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 void 对类型为T的对象应用操作,包含方法void accept(T t);【消费型】
java.util.function.Supplier T 返回类型为T的对象,包含方法 T get(); 【供给型】
java.util.function.Function T R 参数类型T,返回类型R,包含方法 R apply(T t); 【函数型】
java.util.function.Predicate T boolean 参数类型T,返回类型boolean,包含方法 boolean test(T t); 【断言型】
    /**
     * 接口新增:默认方法与静态方法
     *  default 接口默认实现方法是为了让集合类默认实现这些函数式处理,而不用修改现有代码
     *  (List继承于Iterable,接口默认方法不必须实现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:表示该注解能写在类型参数的声明语句中。 类型参数声明如:

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剩余空间容量的百分比,减少为释放空间所导致的垃圾收集

相关文章链接:
<< << << << << << <<<为什么重写equals还要重写hashcode方法
<<<如何自定义注解
<<<十大经典排序算法汇总-动画演示

你可能感兴趣的:(JDK8十大新特性)