jdk8新特性

来源:互联网 发布:淘宝网站首页源代码 编辑:程序博客网 时间:2024/05/20 21:21

jdk8最大特性便是在于提供了函数式接口和Lambda表达式。Functional Interface(函数式接口,简称FI), 即只包含唯一一个抽象方法的接口, 称为FI 。 而 Lambada表达式是基于函数式接口之上的。不多说了,我们直接上代码,看一下jdk8特性的使用:

package jdk8;import java.time.Clock;import java.time.DayOfWeek;import java.time.Instant;import java.time.LocalDate;import java.time.LocalDateTime;import java.time.LocalTime;import java.time.Month;import java.time.ZoneId;import java.time.format.DateTimeFormatter;import java.time.format.FormatStyle;import java.time.temporal.ChronoField;import java.time.temporal.ChronoUnit;import java.util.Arrays;import java.util.Collections;import java.util.Comparator;import java.util.Date;import java.util.HashMap;import java.util.List;import java.util.Locale;import java.util.Map;import java.util.Optional;import java.util.concurrent.Executors;import java.util.concurrent.ThreadLocalRandom;import java.util.function.Consumer;import java.util.function.Function;import java.util.function.Predicate;import java.util.function.Supplier;/*  * jdk7 引入了 ForkJoinPool * divide and conquer : 分而治之 算法 * ForkJoinPool 有如下特点: * 1:work stealing, 当一个任务划分一个新线程时,它将自己推到 deque 的头部. *                    当一个任务执行与另一个未完成任务的合并操作时,它会将另一个任务推到队列头部并执行 *                   当线程的任务队列为空,它将尝试从另一个线程的 deque 的尾部 窃取另一个任务 * 2:避免等待子问题线程返回 *  * ThreadPoolExecutor 和 ForkJoinPool都继承了AbstractExecutorService, * ForkjoinPool使用到了RecursiveAction和RecursiveTask,他们分别表示不需要执行结果和需要返回执行结果的场景。 * 而ThreadPoolExecutor使用Runnable和Callable的参数来分别表示不需要返回值和需要返回值的线程执行对象 *//** *  jdk8 特性 *  *  Java编译器的新特性 *  一、方法参数名称, javac -parameter进行编译,使用Parameter.getName()方法可以取得方法名字, 该属性默认是关闭的。 *  二、Nashorn JavaScript引擎, 使得我们可以在JVM上开发和运行JS应用, 使用jjs运行js文件,如:jjs func.js。例子如下: *      ScriptEngineManager manager = new ScriptEngineManager(); *      ScriptEngine engine = manager.getEngineByName( "JavaScript" ); *      System.out.println( engine.getClass().getName() ); *      System.out.println( "Result:" + engine.eval( "function f() { return 1; }; f() + 1;" ) ); *  三、 类依赖分析器:jdeps, 它可以展示包层级和类层级的Java类依赖关系,它以.class文件、目录或者Jar文件为输入,然后会把依赖关系输出到控制台。 *  四、使用Metaspace(JEP 122)代替持久代(PermGen space)。 *      在JVM参数方面,使用-XX:MetaSpaceSize和-XX:MaxMetaspaceSize代替原来的-XX:PermSize和-XX:MaxPermSize。 */public class Features {    public static void main(String[] args) {        MR();    }    /*     *  特性一:接口的默认方法和静态方法,即接口添加非抽象的方法实现,只需要使用 default关键字即可     *  defalue修饰的方法是不被Lambda表达式访问的     */    interface Formula{        double calculate(int a);        default double sqrt(int a) {            return Math.sqrt(a);        }    }    /*     *  特性二:Lambda 表达式, 任何可以接受一个FI实例的地方,都可以用Lambda表达式     *  lambda: 可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量     */    public static void Lambda(){        List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");        // 老写法        Collections.sort(names, new Comparator<String>() {            @Override            public int compare(String a, String b) {                return b.compareTo(a);            }        });        // jdk1.8 的Lambda 写法        Collections.sort(names, (String a, String b) -> {            return b.compareTo(a);        });        // 对于函数体只有一行代码的,你可以去掉大括号{}以及return关键字        Collections.sort(names, (String a, String b) -> b.compareTo(a));        // Java编译器可以自动推导出参数类型,所以你可以不用再写一次类型        Collections.sort(names, (a,  b) -> b.compareTo(a));        // 上面几种写法,等价下面这种写法        names.sort((a,  b) -> b.compareTo(a));        // 如果表达式不需要参数呢?好吧,那也必须有圆括号        Executors.newSingleThreadExecutor().execute(() -> {/* Runnable do something. */});    }    /*     *  特性三:Functional Interface(函数式接口,以下简称FI), 即只包含唯一一个抽象方法的接口, 称为FI     *  使用 @FunctionalInterface注解, 如 RunnableComparatorPredicateFunctionSupplierConsumerFilter都是FI     */    @FunctionalInterface    interface FI {        public abstract void run();    }    /*     *  特性四:Method References(方法引用, 简称MR), Lambda表达式的代码只有一个简单的方法调用的时候,可以简化为MR     *  即使用 :: 关键字来传递方法或者构造函数引用,     *  MR分为四种:  静态方法\某个特定对象的实例方法\某个类的实例方法\构造函数     */     public static void MR(){        List<String> ints = Arrays.asList("peter", "anna", "mike", "xenia");        // 一、引用 静态方法, 注意:这个方法接受一个特定类型的参数。        ints.sort(String::compareTo); // 升序        // 二、引用 某个特定对象的实例方法, 注意:这个方法接受一个特定类型的参数。        ints.forEach(System.out::println);        // 三、引用 某个特定对象的实例方法,注意:这个方法没有定义入参数        ints.stream().map(String::length);        // 四、引用类的 构造函数, 注意:这个构造器没有参数。        ints.stream().map(StringBuilder::new);     }     // 特性五:Predicate 接口只有一个参数,返回boolean类型    public static void testPredicate(){         /*          *  lambda 声明一个Predicate接口的实现类,实现了Predicate 接口的 test()          *  等价于          *  Predicate<String> predicate = new Predicate<String>(){          *     boolean test(String s){          *         return s.length() > 0;          *     }          *  }          */         Predicate<String> predicate = (s) -> s.length() > 0;         predicate.test("foo");         predicate.negate().test("foo");         // 使用方法引用时, 引用的方法返回值必须是 boolean类型且无参         @SuppressWarnings("unused")         Predicate<String> predicate1 = String::isEmpty;     }     // 特性六:Function 接口一个参数并且返回一个结果,并附带了一些可以和其他函数组合的默认方法(compose, andThen):    public static void testFunction(){        /*          *  Function<String, Integer> toInteger = Integer::valueOf          *  等价于          *  Function<String, Integer> predicate = new Predicate<String, Integer>(){          *     Integer apply(String s){          *         return Integer.valueOf(s);          *     }          *  }          */        Function<String, Integer> toInteger = Integer::valueOf;        Function<String, String> backToString = toInteger.andThen(String::valueOf);        backToString.apply("123");         }    // 特性七:Supplier 接口返回一个任意范型的值,和Function接口不同的是该接口没有任何参数    public static void testSupplier(){        Supplier<Features> fSupplier = Features::new;        fSupplier.get(); // 返回Features实例对象    }    // 特性八:Consumer 接口表示执行在单个参数上的操作    public static void testConsumer(){        Consumer<Features> greeter = (p) -> System.out.println("Hello, ");        greeter.accept(new Features()); // 返回Features实例对象    }    // 特性九:Comparator java中的经典接口, Java 8在此之上添加了多种默认方法    public static void testComparator(){        @SuppressWarnings("unused")        Comparator<String> comparator = (p1, p2) -> p1.compareTo(p2);    }    /*     *  特性十:Optional 不是函数是接口,这是个用来防止NullPointerException异常的辅助类型     *  Optional 被定义为一个简单的容器,其值可能是null或者不是null      *  在Java 8中,不推荐你返回null而是返回Optional。     */    public static void testOptional(){        Optional<String> optional = Optional.of("bam");        optional.isPresent();           // true        optional.get();                 // "bam"        optional.orElse("fallback");    // "bam"        optional.ifPresent((s) -> System.out.println(s.charAt(0)));     // "b"    }    /*     *  特性十一:Stream 不是函数式接口,表示能应用在一组元素上一次执行的操作序列。     *  Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,这样你就可以将多个操作依次串起来。     *  Stream 的创建需要指定一个数据源,比如 java.util.Collection的子类,List或者SetMap不支持     *  Stream 仅仅代表着数据流,并没有数据结构,所以他遍历完一次之后便再也无法遍历     */    public static void testStream(){        List<String> ints = Arrays.asList("peter", "anna", "mike", "xenia");        // 一:Filter 过滤,中间操作, 通过 Predicate 接口来过滤并只保留符合条件的元素。        ints.stream().filter((s) -> s.startsWith("a")).forEach(System.out::println);        /*         *  二:Sort 排序,中间操作,通过 Comparator 接口返回的是排序好后的Stream。如果不指定自定义的Comparator则会使用默认排序。         *  sorted只是创建一个流对象排序的视图,而不会改变原来集合中元素的顺序         */        ints.stream().sorted().forEach(System.out::println);        // 三:Map 映射, 中间操作, 通过 Function 接口将元素根据指定的Function接口来依次将元素转成另外的对象。        ints.stream().map(String::toUpperCase).forEach(System.out::println); // 转大写        // 四:Match 匹配, 最终操作, 通过检测指定的 Predicate 是否匹配整个Stream        ints.stream().allMatch((s) -> s.startsWith("a"));   // 所有满足以a开头,则返回ture        ints.stream().anyMatch((s) -> s.startsWith("a"));   // 只要存在一个满足以a开头,则返回ture        ints.stream().noneMatch((s) -> s.startsWith("a"));  // 不存在以a开头,则返回ture        // 五:Count 计数, 最终操作,返回Stream中元素的个数,返回值类型是longints.stream().filter((s) -> s.startsWith("a")).count();        // 六:Reduce 规约 计数, 最终操作,通过 Optionalstream中的多个元素规约为一个元素。        ints.stream().reduce((s1, s2) -> s1 + "#" + s2);        // 七:forEach是一个最终操作。通过 Consumer 接口进行遍历操作        ints.stream().forEach(System.out::println);        /*         *  八:并行和串行Stream。串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。         *  100 000 次遍历, 并行Stream快了50%之多         */        ints.stream().sorted().count();                 ints.parallelStream().sorted().count();    }    /*     *  特性十二:  Map类型不支持stream,不过Map提供了一些新的有用的方法来处理一些日常任务。     */    public static void testMapFetures(){        Map<Integer, String> map = new HashMap<>();        for (int i = 0; i < 10; i++) {            // 如果map中有对应K映射的V且不为null则直接返回;否则执行put            map.putIfAbsent(i, "val" + i);         }        // compute重映射, ifPresent会判断key对应的v是否是null,不wnull才会compute->否则直接返回null        map.computeIfPresent(3, (num, val) -> val + num);        map.get(3);             // val33        map.computeIfPresent(9, (num, val) -> null);        map.containsKey(9);     // false        map.computeIfAbsent(23, num -> "val" + num);        map.containsKey(23);    // true        map.computeIfAbsent(3, num -> "bam");        map.get(3);             // val33        // Map里删除一个键值全都匹配的项:        map.remove(3, "val3");        map.get(3);             // val33        map.remove(3, "val33");        map.get(3);             // null        // 不存在或为空,返回默认值        map.getOrDefault(42, "not found");         // Merge做的事情是如果键名不存在则插入,否则则对原键对应的值做合并操作并重新插入到mapmap.merge(9, "val9", (value, newValue) -> value.concat(newValue));        map.get(9);             // val9        map.merge(9, "concat", (value, newValue) -> value.concat(newValue));        map.get(9);             // val9concat    }    /*     *  特性十三:  Date API NEW FETURES     */    @SuppressWarnings("unused")    public static void testDateApiFutures(){        // 一、Clock类提供了访问当前日期和时间的方法,Clock是时区敏感的,可以用来取代 System.currentTimeMillis() 来获取当前的微秒数。        Clock clock = Clock.systemDefaultZone();        long millis = clock.millis();        Instant instant = clock.instant();        Date legacyDate = Date.from(instant);   // legacy java.util.Date        /*         *  二、Timezones 时区, 在新API中时区使用ZoneId来表示。         *  时区可以很方便的使用静态方法of来获取到。 时区定义了到UTS时间的时间差,在Instant时间点对象到本地日期对象之间转换的时候是极其重要的。         */        System.out.println(ZoneId.getAvailableZoneIds());        // prints all available timezone ids        ZoneId zone1 = ZoneId.of("Europe/Berlin");        ZoneId zone2 = ZoneId.of("Brazil/East");        System.out.println(zone1.getRules());        System.out.println(zone2.getRules());        /*         *  三、LocalTime 本地时间, 定义了一个没有时区信息的时间。         *  提供了多种工厂方法来简化对象的创建,包括解析时间字符串。         */        LocalTime now1 = LocalTime.now(zone1);        LocalTime now2 = LocalTime.now(zone2);        System.out.println(now1.isBefore(now2));  // false        System.out.println(ChronoUnit.HOURS.between(now1, now2));       // 两个时间相差几小时 -3        System.out.println(ChronoUnit.MINUTES.between(now1, now2));     // 两个时间相差几分钟 -239        LocalTime late = LocalTime.of(23, 59, 59);        System.out.println(late);       // 23:59:59        DateTimeFormatter germanFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withLocale(Locale.GERMAN);        LocalTime leetTime = LocalTime.parse("13:37", germanFormatter);        System.out.println(leetTime);   // 13:37        /*         *  三、LocalDate 本地日期,  表示了一个确切的日期,比如 2014-03-11。该对象值是不可变的.         */        LocalDate today = LocalDate.now();        LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS);        LocalDate yesterday = tomorrow.minusDays(2);        LocalDate independenceDay = LocalDate.of(2014, Month.JULY, 4);        DayOfWeek dayOfWeek = independenceDay.getDayOfWeek();        germanFormatter = DateTimeFormatter .ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.GERMAN);        LocalDate xmas = LocalDate.parse("24.12.2014", germanFormatter);        System.out.println(xmas);   // 2014-12-24        /*         *   四、LocalDateTime 本地日期时间,  LocalDateTimeLocalTime还有LocalDate一样,都是不可变的。         */        LocalDateTime sylvester = LocalDateTime.of(2014, Month.DECEMBER, 31, 23, 59, 59);        dayOfWeek = sylvester.getDayOfWeek();        System.out.println(dayOfWeek);      // WEDNESDAY        Month month = sylvester.getMonth();        System.out.println(month);          // DECEMBER        long minuteOfDay = sylvester.getLong(ChronoField.MINUTE_OF_DAY);        System.out.println(minuteOfDay);    // 1439        // 只要附加上时区信息,就可以将其转换为一个时间点Instant对象,Instant时间点对象可以很容易的转换为老式的java.util.Date        instant = sylvester .atZone(ZoneId.systemDefault()).toInstant();        legacyDate = Date.from(instant);        System.out.println(legacyDate);     // Wed Dec 31 23:59:59 CET 2014    }    /*     *  特性十四:  多重注解     */    //@Path    //@Path    public static void testRepeatAnnotation(){    }    /*     *  特性十五:  并行数组     *  使用parallelSetAll()方法生成20000个随机数,然后使用parallelSort()方法进行排序。     *  这个程序会输出乱序数组和排序数组的前10个元素。     */    public static void testParalleArrays(){        long[] arrayOfLong = new long [ 20000 ];         Arrays.parallelSetAll( arrayOfLong, index -> ThreadLocalRandom.current().nextInt( 1000000 ) );        Arrays.stream( arrayOfLong ).limit( 10 ).forEach( i -> System.out.print( i + " " ) );        System.out.println();        Arrays.parallelSort( arrayOfLong );         Arrays.stream( arrayOfLong ).limit( 10 ).forEach( i -> System.out.print( i + " " ) );        System.out.println();    }}
0 0
原创粉丝点击