JAVA8 新特性学习笔记
ajzx3880
8年前
<h3>语法的新特性:</h3> <h2>一、 接口 <strong>默认方法和静态方法</strong> ,给接口赋予了类的能力,增强了java的灵活性。</h2> <p>接口中可加入default默认方法或static静态方法。</p> <p>可有多个但必须实现其方法体。Java接口中定义了默认方法,实现类不用每个方法都实现一遍了。而且不需要修改继承接口的实现类,就给接口添加了新的方法实现。其给接口赋予了抽象类的能力,增强了java的灵活性。</p> <h2>二、 方法引用</h2> <p>ClassName::methodName (静态方法 + 实例方法 都可使用)</p> <p>super::methodName (超类上的实例方法使用)</p> <p>Class::new (创建新实例时可使用)</p> <p>TypeName[]::new</p> <h2>三、 Lambda表达式(也叫做闭包)</h2> <pre> <code class="language-java">Collections.sort(names, (String a, String b) -> { return b.compareTo(a); }); Collections.sort(names, (String a, String b) -> b.compareTo(a)); Collections.sort(names, (a, b) -> b.compareTo(a));</code></pre> <p>Lambda 作用域 </p> <p>在lambda表达式中可以访问外层局部变量,但不能修改外层局部变量。(闭包的作用域)</p> <p>和本地变量不同的是,lambda内部对于实例的字段或类的静态变量是即可读又可写。</p> <h2>四、 函数式接口</h2> <p>函数式接口 <strong>有且仅有一个抽象方法</strong> ,每一个lambda匹配这个抽象方法。因为static与defualt默认方法不是抽象的,所以可以在函数式接口中自由的添加。</p> <p>函数式接口应该用@FunctionalInterface来注解接口,但可省略。</p> <p>函数式接口的作用是使lambda表达式融入java的类型系统。每一个lambda相当于一种指定类型的函数式接口的实现。</p> <pre> <code class="language-java">@FunctionalInterface public interface MyFuncitonalInterface { void fun(); } MyFuncitonalInterface mf = () -> System.out.println(666); mf.fun();</code></pre> <p>常用javaAPI标准函数接口:</p> <ol> <li> <p>Predicate 断言,一般用来判断是否满足某条件</p> </li> <li> <p>Consumer 接收一个参数,无返回值</p> </li> <li> <p>Function 接收T对象,返回R对象</p> </li> <li> <p>Supplier 类似工厂,调用时会返回一个指定类型的对象</p> </li> <li> <p>UnaryOperator 执行一元操作(与、或、非)</p> </li> <li> <p>BinaryOperator 接收两个参数,返回一个值</p> </li> </ol> <p>一些函数式接口的典型用例:</p> <pre> <code class="language-java">public class Lambda { @FunctionalInterface interface Fun { void foo(); } public static void main(String[] args) throws Exception { // Predicates Predicate<String> predicate = (s) -> s.length() > 0; predicate.test("foo"); // true predicate.negate().test("foo"); // false Predicate<Boolean> nonNull = Objects::nonNull; Predicate<Boolean> isNull = Objects::isNull; Predicate<String> isEmpty = String::isEmpty; Predicate<String> isNotEmpty = isEmpty.negate(); // Functions Function<String, Integer> toInteger = Integer::valueOf; Function<String, String> backToString = toInteger.andThen(String::valueOf);//在toInteger加入apply结束后执行的方法,生成新的Function backToString.apply("123"); // "123" // Suppliers Supplier<Person> personSupplier = Person::new; personSupplier.get(); // new Person // Consumers Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName); greeter.accept(new Person("Luke", "Skywalker")); // Comparators Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName); Person p1 = new Person("John", "Doe"); Person p2 = new Person("Alice", "Wonderland"); comparator.compare(p1, p2); // > 0 comparator.reversed().compare(p1, p2); // < 0 // Runnables Runnable runnable = () -> System.out.println(UUID.randomUUID()); runnable.run(); // Callables Callable<UUID> callable = UUID::randomUUID; callable.call(); } }</code></pre> <p>小结:</p> <p>以上新增的语言特性使Java 能够实现一部分“函数式”的编程范式,可以用简单的函数式风格(例如filter和map)简化笨重的代码。但Java需要用类型来表示它们。如java.util.function中的Predicate、Function和Consumer接口。</p> <h3>java库的新特性</h3> <h2>五、 Stream 流操作</h2> <p>java.util.Stream 表示能应用在一组元素上一次执行的操作序列。</p> <p>Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,这样你就可以将多个操作依次串起来。</p> <p>Stream 的创建需要指定一个数据源,比如 java.util.Collection的子类,List或者Set, Map不支持。通过 Collection.stream() 或者 Collection.parallelStream() 来创建一个Stream。</p> <p>Stream的操作可以串行执行或者并行(parallelStream)执行。</p> <p>常用操作:</p> <p>forEach 遍历</p> <pre> <code class="language-java">stringCollection .stream() .forEach(System.out::println);</code></pre> <p>Filter 过滤</p> <p>过滤通过一个predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作,所以我们可以在过滤后的结果来应用其他Stream操作(比如forEach)。forEach需要一个函数来对过滤后的元素依次执行。forEach是一个最终操作,所以我们不能在forEach之后来执行其他Stream操作。</p> <pre> <code class="language-java">stringCollection .stream() .filter((s) -> s.startsWith("a")) .forEach(System.out::println);</code></pre> <p>Sort 排序</p> <p>排序是一个中间操作,返回的是排序好后的Stream。如果你不指定一个自定义的Comparator则会使用默认排序。需要注意的是,排序只创建了一个排列好后的Stream,而不会影响原有的数据源,排序之后原数据stringCollection是不会被修改的:</p> <pre> <code class="language-java">stringCollection .stream() .sorted() .filter((s) -> s.startsWith("a")) .forEach(System.out::println);</code></pre> <p>Map 映射</p> <p>中间操作map会将元素根据指定的Function接口来依次将元素转成另外的对象,下面的示例展示了将字符串转换为大写字符串。你也可以通过map来讲对象转换成其他类型,map返回的Stream类型是根据你map传递进去的函数的返回值决定的。</p> <pre> <code class="language-java">stringCollection .stream() .map(String::toUpperCase) .sorted((a, b) -> b.compareTo(a)) .forEach(System.out::println);</code></pre> <p>Match 匹配</p> <p>Stream提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。所有的匹配操作都是最终操作,并返回一个boolean类型的值。</p> <pre> <code class="language-java">boolean anyStartsWithA = stringCollection .stream() .anyMatch((s) -> s.startsWith("a")); System.out.println(anyStartsWithA); // true boolean allStartsWithA = stringCollection .stream() .allMatch((s) -> s.startsWith("a")); System.out.println(allStartsWithA); // false boolean noneStartsWithZ = stringCollection .stream() .noneMatch((s) -> s.startsWith("z")); System.out.println(noneStartsWithZ); // true</code></pre> <p>Count 计数</p> <p>计数是一个最终操作,返回Stream中元素的个数,返回值类型是long。</p> <pre> <code class="language-java">long startsWithB = stringCollection .stream() .filter((s) -> s.startsWith("b")) .count();</code></pre> <p>Reduce</p> <p>这是一个最终操作,允许通过指定的函数来讲stream中的多个元素规约为一个元素,规约后的结果是通过Optional接口表示的:</p> <pre> <code class="language-java">Optional<String> reduced = stringCollection .stream() .sorted() .reduce((s1, s2) -> s1 + "#" + s2); reduced.ifPresent(System.out::println);</code></pre> <p>collect获取集合</p> <pre> <code class="language-java">//获取年龄大于12的用户列表 List<User> list = users.parallelStream().filter(p -> p.age > 12) .collect(Collectors.toList()); System.out.println(list);</code></pre> <h2>六、 Optional 处理空指针问题</h2> <p>Optional内部封装了要处理的值value,对外提供了一下方法:</p> <pre> <code class="language-java">//============创建方法=====================================// <T> Optional<T> empty() ;//返回空对象 <T> Optional<T> of(T value);//返回封装value的Optional对象,内部用Objects.requireNonNull,判断value为null的情况抛出NullPointerException <T> Optional<T> ofNullable(T value);//返回一个封装value的Optional对象,value为null的情况返回空的Optional对象 //============使用方法=====================================// T get();// 返回value,若value为nul抛出NoSuchElementException boolean isPresent();//判断value是否存在 void ifPresent(Consumer<? super T> consumer) ;//若value非null,执行consumer.accept(value)方法 Optional<T> filter(Predicate<? super T> predicate);//若value存在并且value符合predicate的判定,返回Optional对象,否则返回空Optional对象 <U> Optional<U> map(Function<? super T, ? extends U> mapper);//若value存在执行mapper.apply(value)并返回Optional对象,否则返回空Optional对象。flatMap略(为空抛出NullPointerException) T orElse(T other);//返回value,若value为null返回other T orElseGet(Supplier<? extends T> other);//返回value,若value为null返回other.get()的返回值 <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X ;//返回value,若value为null抛出exceptionSupplier.get()的返回值</code></pre> <pre> <code class="language-java">//典型用例: //获取字符串s,若为null返回"" String str = Optional.fromNullable(s).orElse(""); //获取车辆对象,若为null则new一个 Car car = Optional.fromNullable(car).orElse(Car::new);</code></pre> <p>其他:</p> <ul> <li> <p>Objects工具类, 对Object空指针问题进行了处理。</p> </li> <li> <p>数组工具类:Arrays.parallelSort 并行排序</p> </li> <li> <p>Map新增方法:</p> </li> </ul> <p>map.forEach((id, val) -> System.out.println(val));</p> <p>map.getOrDefault(42, "not found"); // 没有返回默认值</p> <ul> <li> <p>HashMap 内部结构变为:数组+链表+红黑树(解决hashCode冲突使用链地址法,将key加入链表,当链表长度大于8时转换为红黑树,引入红黑树利用红黑树快速增删改查的特点大程度优化了HashMap的性能。这个数据结构很屌但很复杂(⊙o⊙)?)</p> </li> <li> <p>多重Annotation:允许我们把同一个类型的注解使用多次,只需要给该注解标注一下@Repeatable即可。还增加到两种新的target:@Target({ElementType.TYPE <em>PARAMETER, ElementType.TYPE</em> USE})</p> </li> <li> <p>全新的时间日期API。</p> </li> <li> <p>JVM的新特性:JVM内存永久区已经被metaspace替换(JEP 122)。JVM参数 -XX:PermSize 和 –XX:MaxPermSize被XX:MetaSpaceSize 和 -XX:MaxMetaspaceSize代替。</p> </li> </ul> <p> </p> <p>来自:https://blog.souche.com/java8-xin-te-xing-xue-xi-bi-ji/</p> <p> </p>