一、 接口 默认方法和静态方法 ,给接口赋予了类的能力,增强了java的灵活性。
接口中可加入default默认方法或static静态方法。
可有多个但必须实现其方法体。Java接口中定义了默认方法,实现类不用每个方法都实现一遍了。而且不需要修改继承接口的实现类,就给接口添加了新的方法实现。其给接口赋予了抽象类的能力,增强了java的灵活性。
二、 方法引用
ClassName::methodName (静态方法 + 实例方法 都可使用)
super::methodName (超类上的实例方法使用)
Class::new (创建新实例时可使用)
TypeName[]::new
三、 Lambda表达式(也叫做闭包)
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));
Lambda 作用域
在lambda表达式中可以访问外层局部变量,但不能修改外层局部变量。(闭包的作用域)
和本地变量不同的是,lambda内部对于实例的字段或类的静态变量是即可读又可写。
四、 函数式接口
函数式接口 有且仅有一个抽象方法 ,每一个lambda匹配这个抽象方法。因为static与defualt默认方法不是抽象的,所以可以在函数式接口中自由的添加。
函数式接口应该用@FunctionalInterface来注解接口,但可省略。
函数式接口的作用是使lambda表达式融入java的类型系统。每一个lambda相当于一种指定类型的函数式接口的实现。
@FunctionalInterface public interface MyFuncitonalInterface { void fun(); } MyFuncitonalInterface mf = () -> System.out.println(666); mf.fun();
常用javaAPI标准函数接口:
Predicate
Consumer
Function
Supplier
UnaryOperator
BinaryOperator
一些函数式接口的典型用例:
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(); } }
以上新增的语言特性使Java 能够实现一部分“函数式”的编程范式,可以用简单的函数式风格(例如filter和map)简化笨重的代码。但Java需要用类型来表示它们。如java.util.function中的Predicate、Function和Consumer接口。
五、 Stream 流操作
java.util.Stream 表示能应用在一组元素上一次执行的操作序列。
Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,这样你就可以将多个操作依次串起来。
Stream 的创建需要指定一个数据源,比如 java.util.Collection的子类,List或者Set, Map不支持。通过 Collection.stream() 或者 Collection.parallelStream() 来创建一个Stream。
Stream的操作可以串行执行或者并行(parallelStream)执行。
常用操作:
stringCollection .stream() .forEach(System.out::println);
过滤通过一个predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作,所以我们可以在过滤后的结果来应用其他Stream操作(比如forEach)。forEach需要一个函数来对过滤后的元素依次执行。forEach是一个最终操作,所以我们不能在forEach之后来执行其他Stream操作。
stringCollection .stream() .filter((s) -> s.startsWith("a")) .forEach(System.out::println);
排序是一个中间操作,返回的是排序好后的Stream。如果你不指定一个自定义的Comparator则会使用默认排序。需要注意的是,排序只创建了一个排列好后的Stream,而不会影响原有的数据源,排序之后原数据stringCollection是不会被修改的:
stringCollection .stream() .sorted() .filter((s) -> s.startsWith("a")) .forEach(System.out::println);
中间操作map会将元素根据指定的Function接口来依次将元素转成另外的对象,下面的示例展示了将字符串转换为大写字符串。你也可以通过map来讲对象转换成其他类型,map返回的Stream类型是根据你map传递进去的函数的返回值决定的。
stringCollection .stream() .map(String::toUpperCase) .sorted((a, b) -> b.compareTo(a)) .forEach(System.out::println);
Stream提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。所有的匹配操作都是最终操作,并返回一个boolean类型的值。
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
计数是一个最终操作,返回Stream中元素的个数,返回值类型是long。
long startsWithB = stringCollection .stream() .filter((s) -> s.startsWith("b")) .count();
这是一个最终操作,允许通过指定的函数来讲stream中的多个元素规约为一个元素,规约后的结果是通过Optional接口表示的:
Optional<String> reduced = stringCollection .stream() .sorted() .reduce((s1, s2) -> s1 + "#" + s2); reduced.ifPresent(System.out::println);
collect获取集合
//获取年龄大于12的用户列表 List<User> list = users.parallelStream().filter(p -> p.age > 12) .collect(Collectors.toList()); System.out.println(list);
六、 Optional 处理空指针问题
Optional内部封装了要处理的值value,对外提供了一下方法:
//============创建方法=====================================// <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()的返回值
//典型用例: //获取字符串s,若为null返回"" String str = Optional.fromNullable(s).orElse(""); //获取车辆对象,若为null则new一个 Car car = Optional.fromNullable(car).orElse(Car::new);
Objects工具类, 对Object空指针问题进行了处理。
数组工具类:Arrays.parallelSort 并行排序
Map新增方法:
map.forEach((id, val) -> System.out.println(val));
map.getOrDefault(42, "not found"); // 没有返回默认值
HashMap 内部结构变为:数组+链表+红黑树(解决hashCode冲突使用链地址法,将key加入链表,当链表长度大于8时转换为红黑树,引入红黑树利用红黑树快速增删改查的特点大程度优化了HashMap的性能。这个数据结构很屌但很复杂(⊙o⊙)?)
多重Annotation:允许我们把同一个类型的注解使用多次,只需要给该注解标注一下@Repeatable即可。还增加到两种新的target:@Target({ElementType.TYPE PARAMETER, ElementType.TYPE USE})
全新的时间日期API。
JVM的新特性:JVM内存永久区已经被metaspace替换(JEP 122)。JVM参数 -XX:PermSize 和 –XX:MaxPermSize被XX:MetaSpaceSize 和 -XX:MaxMetaspaceSize代替。