JDK1.8新特性
本文作为JDK1.8学习过程中的总结;便于自己反复查阅温故知新。
接口中的非抽象方法
JDK1.8之前,接口类只能定义抽象方法。但在JDK1.8之后,接口类可以有静态方法,默认方法,也就是说接口中可以有方法的具体实现。那么这么做有什么好处吗?
- 减少了代码量;比如:当一个接口有多个实现类时,提取公共方法到接口中,不用再编写公共类给实现类继承了。
- 对既有的类进行功能扩展, 且不必对这些类重新进行设计。 比如, 只需在Collection接口中增加default Stream stream(), 相应的Set和List接口以及它们的子类都包含此的方法, 不必为每个子类都重新copy这个方法。
public interface UserService {
/**
* 在jdk1.8之前,接口中只能存在抽象方法
*/
void fun1();
/**
* jdk1.8之后可以存在以static修饰的非抽象方法,实现了该接口的实现类对象都可以调用次方法
*/
static void fun2() {
// dosomething
}
/**
* jdk1.8之后可以存在以关键字default修饰的非抽象方法,实现了该接口的实现类对象都可以调用次方法
*/
default void fun3() {
// dosomething
}
}
函数式接口
JDK1.8中引入的lambda表达式、方法引用,都涉及到了方法接口都是为了函数式编程服务
@FunctionalInterface
public interface Converter<F, T> {
/**
* 将某个类型的参数转成另一个类型
* @param t 要转换的对象
* @return 转换后的结果
*/
F converter(T t);
}
Lambda表达式
Lambda实质就是将函数式接口自己实现后得到该接口的对象,然后调用该接口的方法。因为在接口中只是申明了方法签名而没有对方法进行实现,所以在实际操作时符合方法签名的前提下可以任意实现。并且实现一次后可反复调用。
观察main方法中的3中写法,可以发现一种比一种简洁易读、易懂,这个就是lambda的好处。
public class FuncationInterfaceDemo {
public static void main(String[] args) {
String s = "456";
// 在jdk1.8之前,使用匿名内部类需要实现该接口
Converter<Integer, String> converter1 = new Converter<Integer, String>() {
@Override
public Integer converter(String s) {
return Integer.valueOf(s);
}
};
System.out.println(converter1.converter(s));
// jdk1.8及之后可以通过lambda表达式完成
Converter<Integer, String> converter2 = (str) -> {
return Integer.valueOf(str);
};
System.out.println(converter2.converter(s));
// 同时,在jdk1.8之后,如果lambda表达式中的内容是一个现成的方法,那么还可以对它进行简化,也就是方法引用
Converter<Integer, String> converter3 = Integer::valueOf;
System.out.println(converter3.converter(s));
}
}
其他函数接口
public class OtherFunctionInterface {
public static void main(String[] args) {
/*
应用场景:有两个集合需要处理,[1, 2, 3, 5] 找出该集合中的偶数,["a", "ab", "abc", "c"] 找出元素长度是1的
按照以前的写法会对这两个集合进行遍历,稍微封装一下,将处理的过程封装成两个方法,一个方法判断 element % 2 == 0
另一个方法判断 element.length == 1
但是使用了Predicate接口以后,却只要实现一个方法就行了,具体看下面例子
*/
// Predicate 接口接受一个参数,返回boolean类型,方法具体由自己实现
Predicate<String> predicate = (s -> s.length() > 1);
// true
System.out.println(predicate.test("test"));
// false
System.out.println(predicate.negate().test("test"));
// 并且实现了or、and等一些默认方法以及静态方法,可以配合使用
Predicate<String> predicate1 = s -> s.length() == 1;
// false
System.out.println(predicate1.test("123"));
// false
System.out.println(predicate.and(predicate1).test("123"));
// true
System.out.println(predicate.or(predicate1).test("123"));
Integer[] integers = {1, 2, 3, 5};
String[] strings = {"a", "ab", "abc", "c"};
Predicate<Integer> filter1 = integer -> integer % 2 == 0;
Predicate<String> filter2 = s -> s.length() == 1;
filter(integers, filter1);
filter(strings, filter2);
}
/**
* 过滤
* 使用了predicate作为参数,根据具体实现不同,过滤规则也不同
*
* @param arrays 要过滤的数据
* @param predicate 过滤表达式
* @param <T> 泛型
*/
private static <T> void filter(T[] arrays, Predicate<T> predicate) {
for (int i = 0; i < arrays.length; i++) {
if (predicate.test(arrays[i])) {
System.out.println(arrays[i]);
}
}
}
}
optional
有效避免非空检验,较少if 判断
public class OptionDemo {
public static void main(String[] args) {
User user = new User();
// 把指定的值封装为Optional对象
System.out.println(Optional.of(user));
// 如果指定的值为null,则抛出NullPointerException
// System.out.println(Optional.of(null));
// 创建一个空的Optional对象
System.out.println(Optional.empty());
// 与of相同,将对象封装成Optional对象
System.out.println(Optional.ofNullable(user));
// 与of区别,如果是null将返回一个空的Optional对象
System.out.println(Optional.ofNullable(null));
// 如果创建的Optional中有值存在,则返回此值,否则抛出NoSuchElementException
Optional<User> optional = Optional.of(user);
System.out.println(optional.get());
optional = Optional.ofNullable(null);
// System.out.println(optional.get());
optional = Optional.ofNullable(null);
user.username = "test";
// 如果创建的Optional中有值存在,则返回该值,否则返回一个默认值(入参)
System.out.println(optional.orElse(new User()));
System.out.println(optional.orElse(null));
// 如果创建的Optional中有值存在,则返回此值,否则返回一个由Supplier接口生成的值
System.out.println(optional.orElseGet(() -> new User()));
// 如果创建的Optional中有值存在,则返回此值,否则抛出一个由指定的Supplier接口生成的异常
// System.out.println(optional.orElseThrow(() -> new NullPointerException()));
optional = Optional.of(user);
user.username = "xu";
// 如果创建的Optional中的值满足filter中的条件,则返回包含该值的Optional对象,否则返回一个空的Optional对象
System.out.println(optional.filter((u -> u.username != null)));
// 如果创建的Optional中的值存在,对该值执行提供的Function函数调用
System.out.println(optional.map(u -> u.username.replace("x", "xixixi")));
// 如果创建的Optional中的值存在,就对该值执行提供的Function函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象
System.out.println(optional.flatMap(u -> Optional.of(new User())));
optional = Optional.ofNullable(null);
// 如果创建的Optional中的值存在,返回true,否则返回false
System.out.println(optional.isPresent());
optional = Optional.of(user);
user.username = "x";
// 如果创建的Optional中的值存在,则执行该方法的调用,否则什么也不做
optional.ifPresent(s -> System.out.println(s.username));
}
}
流
Stream类似于流,单向,不可往复。可以对集合的所有元素进行筛选,过滤,修改等,但是只能对数据遍历一次,如果需要第二次操作,必须继续创建Stream流。
Stream操作分为三个步骤:创建Stream–>中间操作–>最终操作。
public class StreamDemo {
public static void main(String[] args) {
//直接使用静态方法,获取指定值的顺序排序流
Stream<String> stream1 = Stream.of("aa", "bb", "cc");
String[] strArray = {"a", "b", "c"};
//使用的Arrays类的stream方法
Stream<String> stream2 = Arrays.stream(strArray);
List<String> list = Arrays.asList(strArray);
//直接使用集合获取流
Stream<String> stream3 = list.stream();
// 对数据进行遍历
stream1.forEach(s -> System.out.println(s));
// 流只能使用一次,如果要再次使用,只能再建流
stream1 = Stream.of("aa", "bb", "cc");
stream1.forEach(System.out::println);
// 对数据进行过滤
System.out.println("------------------------------------------------");
stream1 = Stream.of("aa", "bb", "cc");
stream1.filter(s -> s.startsWith("a")).forEach(System.out::println);
// 对数据进行排序
System.out.println("------------------------------------------------");
stream1 = Stream.of("cc", "bb", "aa");
stream1.sorted().forEach(System.out::println);
// 对每个元素进行操作
System.out.println("------------------------------------------------");
stream1 = Stream.of("cc", "bb", "aa");
stream1.map(s -> s.toUpperCase()).forEach(System.out::println);
// 统计,放在流操作的最后面,当使用count之后,流消失
System.out.println("------------------------------------------------");
stream1 = Stream.of("cc", "bb", "aa");
System.out.println(stream1.filter(s -> s.startsWith("a")).count());
System.out.println("------------------------------------------------");
stream1 = Stream.of("cc", "bb", "aa");
stream1.reduce((s1, s2) -> s1 + "-" + s2).ifPresent(System.out::println);
// 即进行串行操作,单线程。时间长
list.stream();
// 并行操作,多线程同时进行。需要时间短
list.parallelStream();
}
}
理解Lambda表达式 - https://blog.csdn.net/GoGleTech/article/details/79454151