新特性简介:
在很多情况下,Java8都能提升应用性能,而无需任何改变或性能调优。
Lambda 表达式、 Streams API 以及现有类的新方法都是提高生产力的重要工具。
Java8 新推出的 Optional 类型在处理 null 值时,能减少 NullPointerExceptions 的可能性,给开发者极大的灵活度。
具体如下:
1.速度更快
Java8 运行应用时速度更快。通常,升级至 Java8 的应用都能得到速度上的提升,即便没有做任何改变或调优。对于为了迎合特定 JVM 而做出调整的应用,这或许并不适用。但 Java8 性能更优的理由还有很多:
(1)数据结构的性能提升:对广受欢迎的 HashMap 进行的基准测试表明,它们在 Java8 中的性能更好。这种提升非常吸引人,你无需学习新的 Streams API 或 Lambda 语法,甚至不需要改变现有的代码,就能提升应用的性能。
① 在之前HashMap采用数组和链表的存储结构,但是现在还除了原有的数组和链表,还添加了红黑数,使得查询的效率更高。
a.HashMap本质是一个散列表,存储元素为键值对;
b.HashMap继承AbstractMap,实现了Map、Cloneable、java.io.Serializable接口;
c.HashMap的是线程不安全的,它的key、value都可以为null;
final int loadFacotr
static final float DEFAULT_LOAD_FACTOR: 默认装填因子0.75,如果当前键值对个数 >= HashMap最大容量*装填因子,进行rehash操作;
int threshold
static final int TREEIFY_THRESHOLD: JDK1.8 新加,Entry链表最大长度,当桶中节点数目大于该长度时,将链表转成红黑树存储;
static final int UNTREEIFY_THRESHOLD:JDK1.8 新加,当桶中节点数小于该长度,将红黑树转为链表存储;
static final int DEFAULT_INITIAL_CAPACITY: 默认键值队个数为16;
transient Node<K, V>[] table:键值对数组,长度动态增加,但是总为2的幂;用transient修饰表示对象序列化时该字段不可被序列化;
② ConcurrentHashMap 原理:在JDK1.6中,ConcurrentHashMap将数据分成一段一段存储,给每一段数据配一把锁,当一个线程获得锁互斥访问一个段数据时,其他段的数据也可被其他线程访问;每个Segment拥有一把可重入锁,因此ConcurrentHashMap的分段锁数目即为Segment数组长度。ConcurrentHashMap结构:每一个segment都是一个HashEntry<K,V>[] table, table中的每一个元素本质上都是一个HashEntry的单向队列(单向链表实现)。每一个segment都是一个HashEntry<K,V>[] table, table中的每一个元素本质上都是一个HashEntry的单向队列。
在JDK1.8中采用CAS(Compare And Swap)无锁算法算法:CAS算法包含三个参数CAS(V, E, N),判断预期值E和内存旧值是否相同(Compare),如果相等用新值N覆盖旧值V(Swap),否则失败; 当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,其他线程失败(失败线程不会被阻塞,而是被告知“失败”,可以继续尝试),CAS在硬件层面可以被编译为机器指令执行,因此性能高于基于锁占有方式实现线程安全。
与JDK1.6相比JDK1.8具有如下优势:
a.JDK 1.8取消类segments字段,直接用table数组存储键值对,JDK1.6中每个bucket中键值对组织方式是单向链表,查找复杂度是O(n),JDK1.8中当链表长度超过TREEIFY_THRESHOLD时,链表转换为红黑树,查询复杂度可以降低到O(log n),改进性能;
b.JDK1.8中,一个线程每次对一个桶(链表 or 红黑树)进行加锁,其他线程仍然可以访问其他桶;
c.ConcurrentHashMap底层数据结构与HashMap相同,仍然采用table数组+链表+红黑树结构;
一个线程进行put/remove操作时,对桶(链表 or 红黑树)加上synchronized独占锁;
ConcurrentHashMap采用CAS算法保证线程安全;
(2)垃圾回收器提升:通常,Java 应用性能取决于垃圾回收的效率。的确,糟糕的垃圾回收会很大程度上影响应用性能。Java8 对垃圾回收做了很多改变,能有效提升性能并简化调优。最为人熟知的改变是 PermGen 的移除与 Metaspace 的引入。
(3)Fork/Join 速度提升:fork/join 框架是在 Java7 中首次引入的,目的是简化使用 JVM 的并发程序。Java8 中投入了很多努力进一步提升该框架。现在,fork/join 在 Streams API 中用于并发操作。
此外,Java8 中还包含诸多改进以支持并发。Oracle 在 JDK 8 中总结了这些性能提升。
2.Lambda表达式
Lambda表达式的目的使得代码更少,Java 经常被人们诟病其样本代码太多。为此,Java8 新的 API 采用了更具功能性的方式,专注于实现什么而不是如何实现。
Java8 中的 Lambda 表达式不仅是 Java 已有的匿名内部类,Java8 推出之前传递行为的方法之外的语法糖衣。Lambda 表达式采用了 Java 7 的内部改变,因此运用起来相当流畅。想了解如何使用 Lambda 表达式简化代码,请继续阅读。
(1)Lambdal表达试代码简单示例:
[java] view plain copy
- public class TestLambda1 {
- //原来的匿名内部类
- @Test
- public void test1(){
- Comparator<String> com = new Comparator<String>(){
- @Override
- public int compare(String o1, String o2) {
- return Integer.compare(o1.length(), o2.length());
- }
- };
- TreeSet<String> ts = new TreeSet<>(com);
- TreeSet<String> ts2 = new TreeSet<>(new Comparator<String>(){
- @Override
- public int compare(String o1, String o2) {
- return Integer.compare(o1.length(), o2.length());
- }
- });
- }
- //现在的 Lambda 表达式
- @Test
- public void test2(){
- Comparator<String> com = (x, y) -> Integer.compare(x.length(), y.length());
- TreeSet<String> ts = new TreeSet<>(com);
- }
- List<Employee> emps = Arrays.asList(
- new Employee(101, "张三", 18, 9999.99),
- new Employee(102, "李四", 59, 6666.66),
- new Employee(103, "王五", 28, 3333.33),
- new Employee(104, "赵六", 8, 7777.77),
- new Employee(105, "田七", 38, 5555.55)
- );
- //需求:获取公司中年龄小于 35 的员工信息
- public List<Employee> filterEmployeeAge(List<Employee> emps){
- List<Employee> list = new ArrayList<>();
- for (Employee emp : emps) {
- if(emp.getAge() <= 35){
- list.add(emp);
- }
- }
- return list;
- }
- @Test
- public void test3(){
- List<Employee> list = filterEmployeeAge(emps);
- for (Employee employee : list) {
- System.out.println(employee);
- }
- }
- //需求:获取公司中工资大于 5000 的员工信息
- public List<Employee> filterEmployeeSalary(List<Employee> emps){
- List<Employee> list = new ArrayList<>();
- for (Employee emp : emps) {
- if(emp.getSalary() >= 5000){
- list.add(emp);
- }
- }
- return list;
- }
- //优化方式一:策略设计模式
- public List<Employee> filterEmployee(List<Employee> emps, MyPredicate<Employee> mp){
- List<Employee> list = new ArrayList<>();
- for (Employee employee : emps) {
- if(mp.test(employee)){
- list.add(employee);
- }
- }
- return list;
- }
- @Test
- public void test4(){
- List<Employee> list = filterEmployee(emps, new FilterEmployeeForAge());
- for (Employee employee : list) {
- System.out.println(employee);
- }
- System.out.println("------------------------------------------");
- List<Employee> list2 = filterEmployee(emps, new FilterEmployeeForSalary());
- for (Employee employee : list2) {
- System.out.println(employee);
- }
- }
- //优化方式二:匿名内部类
- @Test
- public void test5(){
- List<Employee> list = filterEmployee(emps, new MyPredicate<Employee>() {
- @Override
- public boolean test(Employee t) {
- return t.getId() <= 103;
- }
- });
- for (Employee employee : list) {
- System.out.println(employee);
- }
- }
- //优化方式三:Lambda 表达式
- @Test
- public void test6(){
- List<Employee> list = filterEmployee(emps, (e) -> e.getAge() <= 35);
- list.forEach(System.out::println);
- System.out.println("------------------------------------------");
- List<Employee> list2 = filterEmployee(emps, (e) -> e.getSalary() >= 5000);
- list2.forEach(System.out::println);
- }
- //优化方式四:Stream API
- @Test
- public void test7(){
- emps.stream()
- .filter((e) -> e.getAge() <= 35)
- .forEach(System.out::println);
- System.out.println("----------------------------------------------");
- emps.stream()
- .map(Employee::getName)
- .limit(3)
- .sorted()
- .forEach(System.out::println);
- }
- }
(2)Lambdal语法格式介绍
[java] view plain copy
- /*
- * 一、Lambda 表达式的基础语法:Java8中引入了一个新的操作符 "->" 该操作符称为箭头操作符或 Lambda 操作符
- * 箭头操作符将 Lambda 表达式拆分成两部分:
- *
- * 左侧:Lambda 表达式的参数列表
- * 右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体
- *
- * 语法格式一:无参数,无返回值
- * () -> System.out.println("Hello Lambda!");
- *
- * 语法格式二:有一个参数,并且无返回值
- * (x) -> System.out.println(x)
- *
- * 语法格式三:若只有一个参数,小括号可以省略不写
- * x -> System.out.println(x)
- *
- * 语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
- * Comparator<Integer> com = (x, y) -> {
- * System.out.println("函数式接口");
- * return Integer.compare(x, y);
- * };
- *
- * 语法格式五:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写
- * Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
- *
- * 语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
- * (Integer x, Integer y) -> Integer.compare(x, y);
- *
- * 上联:左右遇一括号省
- * 下联:左侧推断类型省
- * 横批:能省则省
- *
- * 二、Lambda 表达式需要“函数式接口”的支持
- * 函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。 可以使用注解 @FunctionalInterface 修饰
- * 可以检查是否是函数式接口
- */
- public class TestLambda2 {
- @Test
- public void test1(){
- int num = 0;//jdk 1.7 前,必须是 final
- Runnable r = new Runnable() {
- @Override
- public void run() {
- System.out.println("Hello World!" + num);
- }
- };
- r.run();
- System.out.println("-------------------------------");
- Runnable r1 = () -> System.out.println("Hello Lambda!");
- r1.run();
- }
- @Test
- public void test2(){
- Consumer<String> con = x -> System.out.println(x);
- con.accept("我硅谷威武!");
- }
- @Test
- public void test3(){
- Comparator<Integer> com = (x, y) -> {
- System.out.println("函数式接口");
- return Integer.compare(x, y);
- };
- }
- @Test
- public void test4(){
- Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
- }
- @Test
- public void test5(){
- List<String> list = new ArrayList<>();
- show(new HashMap<>());
- }
- public void show(Map<String, Integer> map){
- }
- //需求:对一个数进行运算
- @Test
- public void test6(){
- Integer num = operation(100, (x) -> x * x);
- System.out.println(num);
- System.out.println(operation(200, (y) -> y + 200));
- }
- public Integer operation(Integer num, MyFun mf){
- return mf.getValue(num);
- }
- }
3.函数式接口
Lambda表达式是如何在java的类型系统中表示的呢?每一个lambda表达式都对应一个类型,通常是接口类型。而“函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。因为 默认方法 不算抽象方法,所以你也可以给你的函数式接口添加默认方法。
我们可以将lambda表达式当作任意只包含一个抽象方法的接口类型,确保你的接口一定达到这个要求,你只需要给你的接口添加 @FunctionalInterface 注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。
[java] view plain copy
- @FunctionalInterface
- interface Converter<F, T> {
- T convert(F from);
- }
- Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
- Integer converted = converter.convert("123");
- System.out.println(converted);
需要注意如果@FunctionalInterface如果没有指定,上面的代码也是对的。将lambda表达式映射到一个单方法的接口上,这种做法在Java 8之前就有别的语言实现,比如Rhino JavaScript解释器,如果一个函数参数接收一个单方法的接口而你传递的是一个function,Rhino 解释器会自动做一个单接口的实例到function的适配器,典型的应用场景有 org.w3c.dom.events.EventTarget 的addEventListener 第二个参数 EventListener。
Java8 内置的四大核心函数式接口
[java] view plain copy
- public class TestLambda3 {
- //Predicate<T> 断言型接口:
- @Test
- public void test4(){
- List<String> list = Arrays.asList("Hello", "guigu", "Lambda", "www", "ok");
- List<String> strList = filterStr(list, (s) -> s.length() > 3);
- for (String str : strList) {
- System.out.println(str);
- }
- }
- //需求:将满足条件的字符串,放入集合中
- public List<String> filterStr(List<String> list, Predicate<String> pre){
- List<String> strList = new ArrayList<>();
- for (String str : list) {
- if(pre.test(str)){
- strList.add(str);
- }
- }
- return strList;
- }
- //Function<T, R> 函数型接口:
- @Test
- public void test3(){
- String newStr = strHandler("\t\t\t 我尚硅谷威武 ", (str) -> str.trim());
- System.out.println(newStr);
- String subStr = strHandler("我尚硅谷威武", (str) -> str.substring(2, 5));
- System.out.println(subStr);
- }
- //需求:用于处理字符串
- public String strHandler(String str, Function<String, String> fun){
- return fun.apply(str);
- }
- //Supplier<T> 供给型接口 :
- @Test
- public void test2(){
- List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100));
- for (Integer num : numList) {
- System.out.println(num);
- }
- }
- //需求:产生指定个数的整数,并放入集合中
- public List<Integer> getNumList(int num, Supplier<Integer> sup){
- List<Integer> list = new ArrayList<>();
- for (int i = 0; i < num; i++) {
- Integer n = sup.get();
- list.add(n);
- }
- return list;
- }
- //Consumer<T> 消费型接口 :
- @Test
- public void test1(){
- happy(10000, (m) -> System.out.println("你们Tom喜欢大宝剑,每次消费:" + m + "元"));
- }
- public void happy(double money, Consumer<Double> con){
- con.accept(money);
- }
- }
4.方法引用与构造器引用
[java] view plain copy
- /*
- * 一、方法引用:若 Lambda 体中的功能,已经有方法提供了实现,可以使用方法引用
- * (可以将方法引用理解为 Lambda 表达式的另外一种表现形式)
- *
- * 1. 对象的引用 :: 实例方法名
- *
- * 2. 类名 :: 静态方法名
- *
- * 3. 类名 :: 实例方法名
- *
- * 注意:
- * ①方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致!
- * ②若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName
- *
- * 二、构造器引用 :构造器的参数列表,需要与函数式接口中参数列表保持一致!
- *
- * 1. 类名 :: new
- *
- * 三、数组引用
- *
- * 类型[] :: new;
- *
- *
- */
- public class TestMethodRef {
- //数组引用
- @Test
- public void test8(){
- Function<Integer, String[]> fun = (args) -> new String[args];
- String[] strs = fun.apply(10);
- System.out.println(strs.length);
- System.out.println("--------------------------");
- Function<Integer, Employee[]> fun2 = Employee[] :: new;
- Employee[] emps = fun2.apply(20);
- System.out.println(emps.length);
- }
- //构造器引用
- @Test
- public void test7(){
- Function<String, Employee> fun = Employee::new;
- BiFunction<String, Integer, Employee> fun2 = Employee::new;
- }
- @Test
- public void test6(){
- Supplier<Employee> sup = () -> new Employee();
- System.out.println(sup.get());
- System.out.println("------------------------------------");
- Supplier<Employee> sup2 = Employee::new;
- System.out.println(sup2.get());
- }
- //类名 :: 实例方法名
- @Test
- public void test5(){
- BiPredicate<String, String> bp = (x, y) -> x.equals(y);
- System.out.println(bp.test("abcde", "abcde"));
- System.out.println("-----------------------------------------");
- BiPredicate<String, String> bp2 = String::equals;
- System.out.println(bp2.test("abc", "abc"));
- System.out.println("-----------------------------------------");
- Function<Employee, String> fun = (e) -> e.show();
- System.out.println(fun.apply(new Employee()));
- System.out.println("-----------------------------------------");
- Function<Employee, String> fun2 = Employee::show;
- System.out.println(fun2.apply(new Employee()));
- }
- //类名 :: 静态方法名
- @Test
- public void test4(){
- Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
- System.out.println("-------------------------------------");
- Comparator<Integer> com2 = Integer::compare;
- }
- @Test
- public void test3(){
- BiFunction<Double, Double, Double> fun = (x, y) -> Math.max(x, y);
- System.out.println(fun.apply(1.5, 22.2));
- System.out.println("--------------------------------------------------");
- BiFunction<Double, Double, Double> fun2 = Math::max;
- System.out.println(fun2.apply(1.2, 1.5));
- }
- //对象的引用 :: 实例方法名
- @Test
- public void test2(){
- Employee emp = new Employee(101, "张三", 18, 9999.99);
- Supplier<String> sup = () -> emp.getName();
- System.out.println(sup.get());
- System.out.println("----------------------------------");
- Supplier<String> sup2 = emp::getName;
- System.out.println(sup2.get());
- }
- @Test
- public void test1(){
- PrintStream ps = System.out;
- Consumer<String> con = (str) -> ps.println(str);
- con.accept("Hello World!");
- System.out.println("--------------------------------");
- Consumer<String> con2 = ps::println;
- con2.accept("Hello Java8!");
- Consumer<String> con3 = System.out::println;
- }
- }
5.Stream API
Stream API 的操作步骤:
1. 创建 Stream
2. 中间操作
3. 终止操作(终端操作)
(1)创建 Stream
[java] view plain copy
- public class TestStreamaAPI {
- //1. 创建 Stream
- @Test
- public void test1(){
- //1. Collection 提供了两个方法 stream() 与 parallelStream()
- List<String> list = new ArrayList<>();
- Stream<String> stream = list.stream(); //获取一个顺序流
- Stream<String> parallelStream = list.parallelStream(); //获取一个并行流
- //2. 通过 Arrays 中的 stream() 获取一个数组流
- Integer[] nums = new Integer[10];
- Stream<Integer> stream1 = Arrays.stream(nums);
- //3. 通过 Stream 类中静态方法 of()
- Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6);
- //4. 创建无限流
- //迭代
- Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2).limit(10);
- stream3.forEach(System.out::println);
- //生成
- Stream<Double> stream4 = Stream.generate(Math::random).limit(2);
- stream4.forEach(System.out::println);
- }
- }
(2)中间操作
[java] view plain copy
- //中间操作
- public class TestStreamAPI1 {
- List<Employee> emps = Arrays.asList(
- new Employee(102, "李四", 59, 6666.66),
- new Employee(101, "张三", 18, 9999.99),
- new Employee(103, "王五", 28, 3333.33),
- new Employee(104, "赵六", 8, 7777.77),
- new Employee(104, "赵六", 8, 7777.77),
- new Employee(104, "赵六", 8, 7777.77),
- new Employee(105, "田七", 38, 5555.55)
- );
- /*
- 筛选与切片
- filter——接收 Lambda , 从流中排除某些元素。
- limit——截断流,使其元素不超过给定数量。
- skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
- distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
- */
- //内部迭代:迭代操作 Stream API 内部完成
- @Test
- public void test1(){
- //所有的中间操作不会做任何的处理
- Stream<Employee> stream = emps.stream()
- .filter((e) -> {
- System.out.println("测试中间操作");
- return e.getAge() <= 35;
- });
- //只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”
- stream.forEach(System.out::println);
- }
- //外部迭代
- @Test
- public void test2(){
- Iterator<Employee> it = emps.iterator();
- while(it.hasNext()){
- System.out.println(it.next());
- }
- }
- @Test
- public void test3(){
- emps.stream()
- .filter((e) -> {
- System.out.println("短路!"); // && ||
- return e.getSalary() >= 5000;
- }).limit(3)
- .forEach(System.out::println);
- }
- @Test
- public void test4(){
- emps.parallelStream()
- .filter((e) -> e.getSalary() >= 5000)
- .skip(2)
- .forEach(System.out::println);
- }
- @Test
- public void test5(){
- emps.stream()
- .distinct()
- .forEach(System.out::println);
- }
- /*
- 映射
- map——接收 Lambda , 将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
- flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
- */
- @Test
- public void test6(){
- Stream<String> str = emps.stream()
- .map((e) -> e.getName());
- System.out.println("-------------------------------------------");
- List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
- Stream<String> stream = strList.stream()
- .map(String::toUpperCase);
- stream.forEach(System.out::println);
- Stream<Stream<Character>> stream2 = strList.stream()
- .map(TestStreamAPI1::filterCharacter);
- stream2.forEach((sm) -> {
- sm.forEach(System.out::println);
- });
- System.out.println("---------------------------------------------");
- Stream<Character> stream3 = strList.stream()
- .flatMap(TestStreamAPI1::filterCharacter);
- stream3.forEach(System.out::println);
- }
- public static Stream<Character> filterCharacter(String str){
- List<Character> list = new ArrayList<>();
- for (Character ch : str.toCharArray()) {
- list.add(ch);
- }
- return list.stream();
- }
- /*
- sorted()——自然排序
- sorted(Comparator com)——定制排序
- */
- @Test
- public void test7(){
- emps.stream()
- .map(Employee::getName)
- .sorted()
- .forEach(System.out::println);
- System.out.println("------------------------------------");
- emps.stream()
- .sorted((x, y) -> {
- if(x.getAge() == y.getAge()){
- return x.getName().compareTo(y.getName());
- }else{
- return Integer.compare(x.getAge(), y.getAge());
- }
- }).forEach(System.out::println);
- }
- }
(3)终止操作
[java] view plain copy
- //3. 终止操作
- /*
- allMatch——检查是否匹配所有元素
- anyMatch——检查是否至少匹配一个元素
- noneMatch——检查是否没有匹配的元素
- findFirst——返回第一个元素
- findAny——返回当前流中的任意元素
- count——返回流中元素的总个数
- max——返回流中最大值
- min——返回流中最小值
- */
- public class TestStreamAPI2 {
- List<Employee> emps = Arrays.asList(
- new Employee(102, "李四", 59, 6666.66, Status.BUSY),
- new Employee(101, "张三", 18, 9999.99, Status.FREE),
- new Employee(103, "王五", 28, 3333.33, Status.VOCATION),
- new Employee(104, "赵六", 8, 7777.77, Status.BUSY),
- new Employee(104, "赵六", 8, 7777.77, Status.FREE),
- new Employee(104, "赵六", 8, 7777.77, Status.FREE),
- new Employee(105, "田七", 38, 5555.55, Status.BUSY)
- );
- @Test
- public void test1(){
- boolean bl = emps.stream()
- .allMatch((e) -> e.getStatus().equals(Status.BUSY));
- System.out.println(bl);
- boolean bl1 = emps.stream()
- .anyMatch((e) -> e.getStatus().equals(Status.BUSY));
- System.out.println(bl1);
- boolean bl2 = emps.stream()
- .noneMatch((e) -> e.getStatus().equals(Status.BUSY));
- System.out.println(bl2);
- }
- @Test
- public void test2(){
- Optional<Employee> op = emps.stream()
- .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
- .findFirst();
- System.out.println(op.get());
- System.out.println("--------------------------------");
- Optional<Employee> op2 = emps.parallelStream()
- .filter((e) -> e.getStatus().equals(Status.FREE))
- .findAny();
- System.out.println(op2.get());
- }
- @Test
- public void test3(){
- long count = emps.stream()
- .filter((e) -> e.getStatus().equals(Status.FREE))
- .count();
- System.out.println(count);
- Optional<Double> op = emps.stream()
- .map(Employee::getSalary)
- .max(Double::compare);
- System.out.println(op.get());
- Optional<Employee> op2 = emps.stream()
- .min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
- System.out.println(op2.get());
- }
- //注意:流进行了终止操作后,不能再次使用
- @Test
- public void test4(){
- Stream<Employee> stream = emps.stream()
- .filter((e) -> e.getStatus().equals(Status.FREE));
- long count = stream.count();
- stream.map(Employee::getSalary)
- .max(Double::compare);
- }
- @Test
- public void test5(){
- List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
- Integer sum = list.stream()
- .reduce(0, (x, y) -> x + y);
- System.out.println(sum);
- System.out.println("----------------------------------------");
- Optional<Double> op = emps.stream()
- .map(Employee::getSalary)
- .reduce(Double::sum);
- System.out.println(op.get());
- }
- //需求:搜索名字中 “六” 出现的次数
- @Test
- public void test6(){
- Optional<Integer> sum = emps.stream()
- .map(Employee::getName)
- .flatMap(TestStreamAPI1::filterCharacter)
- .map((ch) -> {
- if(ch.equals('六'))
- return 1;
- else
- return 0;
- }).reduce(Integer::sum);
- System.out.println(sum.get());
- }
- //collect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
- @Test
- public void test7(){
- List<String> list = emps.stream()
- .map(Employee::getName)
- .collect(Collectors.toList());
- list.forEach(System.out::println);
- System.out.println("----------------------------------");
- Set<String> set = emps.stream()
- .map(Employee::getName)
- .collect(Collectors.toSet());
- set.forEach(System.out::println);
- System.out.println("----------------------------------");
- HashSet<String> hs = emps.stream()
- .map(Employee::getName)
- .collect(Collectors.toCollection(HashSet::new));
- hs.forEach(System.out::println);
- }
- @Test
- public void test8(){
- Optional<Double> max = emps.stream()
- .map(Employee::getSalary)
- .collect(Collectors.maxBy(Double::compare));
- System.out.println(max.get());
- Optional<Employee> op = emps.stream()
- .collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
- System.out.println(op.get());
- Double sum = emps.stream()
- .collect(Collectors.summingDouble(Employee::getSalary));
- System.out.println(sum);
- Double avg = emps.stream()
- .collect(Collectors.averagingDouble(Employee::getSalary));
- System.out.println(avg);
- Long count = emps.stream()
- .collect(Collectors.counting());
- System.out.println(count);
- System.out.println("--------------------------------------------");
- DoubleSummaryStatistics dss = emps.stream()
- .collect(Collectors.summarizingDouble(Employee::getSalary));
- System.out.println(dss.getMax());
- }
- //分组
- @Test
- public void test9(){
- Map<Status, List<Employee>> map = emps.stream()
- .collect(Collectors.groupingBy(Employee::getStatus));
- System.out.println(map);
- }
- //多级分组
- @Test
- public void test10(){
- Map<Status, Map<String, List<Employee>>> map = emps.stream()
- .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
- if(e.getAge() >= 60)
- return "老年";
- else if(e.getAge() >= 35)
- return "中年";
- else
- return "成年";
- })));
- System.out.println(map);
- }
- //分区
- @Test
- public void test11(){
- Map<Boolean, List<Employee>> map = emps.stream()
- .collect(Collectors.partitioningBy((e) -> e.getSalary() >= 5000));
- System.out.println(map);
- }
- @Test
- public void test12(){
- String str = emps.stream()
- .map(Employee::getName)
- .collect(Collectors.joining("," , "----", "----"));
- System.out.println(str);
- }
- @Test
- public void test13(){
- Optional<Double> sum = emps.stream()
- .map(Employee::getSalary)
- .collect(Collectors.reducing(Double::sum));
- System.out.println(sum.get());
- }
- }
6.接口中的默认方法与静态方法
7.新时间日期API
(1) TestSimpleDateFormat
[java] view plain copy
- public class TestSimpleDateFormat {
- public static void main(String[] args) throws Exception {
- DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
- Callable<LocalDate> task = new Callable<LocalDate>() {
- @Override
- public LocalDate call() throws Exception {
- LocalDate ld = LocalDate.parse("20161121", dtf);
- return ld;
- }
- };
- ExecutorService pool = Executors.newFixedThreadPool(10);
- List<Future<LocalDate>> results = new ArrayList<>();
- for (int i = 0; i < 10; i++) {
- results.add(pool.submit(task));
- }
- for (Future<LocalDate> future : results) {
- System.out.println(future.get());
- }
- pool.shutdown();
- }
- }
(2) TestLocalDateTime
[java] view plain copy
- public class TestLocalDateTime {
- //6.ZonedDate、ZonedTime、ZonedDateTime : 带时区的时间或日期
- @Test
- public void test7(){
- LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
- System.out.println(ldt);
- ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("US/Pacific"));
- System.out.println(zdt);
- }
- @Test
- public void test6(){
- Set<String> set = ZoneId.getAvailableZoneIds();
- set.forEach(System.out::println);
- }
- //5. DateTimeFormatter : 解析和格式化日期或时间
- @Test
- public void test5(){
- // DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE;
- DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss E");
- LocalDateTime ldt = LocalDateTime.now();
- String strDate = ldt.format(dtf);
- System.out.println(strDate);
- LocalDateTime newLdt = ldt.parse(strDate, dtf);
- System.out.println(newLdt);
- }
- //4. TemporalAdjuster : 时间校正器
- @Test
- public void test4(){
- LocalDateTime ldt = LocalDateTime.now();
- System.out.println(ldt);
- LocalDateTime ldt2 = ldt.withDayOfMonth(10);
- System.out.println(ldt2);
- LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
- System.out.println(ldt3);
- //自定义:下一个工作日
- LocalDateTime ldt5 = ldt.with((l) -> {
- LocalDateTime ldt4 = (LocalDateTime) l;
- DayOfWeek dow = ldt4.getDayOfWeek();
- if(dow.equals(DayOfWeek.FRIDAY)){
- return ldt4.plusDays(3);
- }else if(dow.equals(DayOfWeek.SATURDAY)){
- return ldt4.plusDays(2);
- }else{
- return ldt4.plusDays(1);
- }
- });
- System.out.println(ldt5);
- }
- //3.
- //Duration : 用于计算两个“时间”间隔
- //Period : 用于计算两个“日期”间隔
- @Test
- public void test3(){
- Instant ins1 = Instant.now();
- System.out.println("--------------------");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- }
- Instant ins2 = Instant.now();
- System.out.println("所耗费时间为:" + Duration.between(ins1, ins2));
- System.out.println("----------------------------------");
- LocalDate ld1 = LocalDate.now();
- LocalDate ld2 = LocalDate.of(2011, 1, 1);
- Period pe = Period.between(ld2, ld1);
- System.out.println(pe.getYears());
- System.out.println(pe.getMonths());
- System.out.println(pe.getDays());
- }
- //2. Instant : 时间戳。 (使用 Unix 元年 1970年1月1日 00:00:00 所经历的毫秒值)
- @Test
- public void test2(){
- Instant ins = Instant.now(); //默认使用 UTC 时区
- System.out.println(ins);
- OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8));
- System.out.println(odt);
- System.out.println(ins.getNano());
- Instant ins2 = Instant.ofEpochSecond(5);
- System.out.println(ins2);
- }
- //1. LocalDate、LocalTime、LocalDateTime
- @Test
- public void test1(){
- LocalDateTime ldt = LocalDateTime.now();
- System.out.println(ldt);
- LocalDateTime ld2 = LocalDateTime.of(2016, 11, 21, 10, 10, 10);
- System.out.println(ld2);
- LocalDateTime ldt3 = ld2.plusYears(20);
- System.out.println(ldt3);
- LocalDateTime ldt4 = ld2.minusMonths(2);
- System.out.println(ldt4);
- System.out.println(ldt.getYear());
- System.out.println(ldt.getMonthValue());
- System.out.println(ldt.getDayOfMonth());
- System.out.println(ldt.getHour());
- System.out.println(ldt.getMinute());
- System.out.println(ldt.getSecond());
- }
- }
8.其他新特性
Optional 容器类:用于尽量避免空指针异常
[java] view plain copy
- /*
- * 一、Optional 容器类:用于尽量避免空指针异常
- * Optional.of(T t) : 创建一个 Optional 实例
- * Optional.empty() : 创建一个空的 Optional 实例
- * Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
- * isPresent() : 判断是否包含值
- * orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
- * orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
- * map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
- * flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
- */
- public class TestOptional {
- @Test
- public void test4(){
- Optional<Employee> op = Optional.of(new Employee(101, "张三", 18, 9999.99));
- Optional<String> op2 = op.map(Employee::getName);
- System.out.println(op2.get());
- Optional<String> op3 = op.flatMap((e) -> Optional.of(e.getName()));
- System.out.println(op3.get());
- }
- @Test
- public void test3(){
- Optional<Employee> op = Optional.ofNullable(new Employee());
- if(op.isPresent()){
- System.out.println(op.get());
- }
- Employee emp = op.orElse(new Employee("张三"));
- System.out.println(emp);
- Employee emp2 = op.orElseGet(() -> new Employee());
- System.out.println(emp2);
- }
- @Test
- public void test2(){
- /*Optional<Employee> op = Optional.ofNullable(null);
- System.out.println(op.get());*/
- // Optional<Employee> op = Optional.empty();
- // System.out.println(op.get());
- }
- @Test
- public void test1(){
- Optional<Employee> op = Optional.of(new Employee());
- Employee emp = op.get();
- System.out.println(emp);
- }
- @Test
- public void test5(){
- Man man = new Man();
- String name = getGodnessName(man);
- System.out.println(name);
- }
- //需求:获取一个男人心中女神的名字
- public String getGodnessName(Man man){
- if(man != null){
- Godness g = man.getGod();
- if(g != null){
- return g.getName();
- }
- }
- return "苍老师";
- }
- //运用 Optional 的实体类
- @Test
- public void test6(){
- Optional<Godness> godness = Optional.ofNullable(new Godness("林志玲"));
- Optional<NewMan> op = Optional.ofNullable(new NewMan(godness));
- String name = getGodnessName2(op);
- System.out.println(name);
- }
- public String getGodnessName2(Optional<NewMan> man){
- return man.orElse(new NewMan())
- .getGodness()
- .orElse(new Godness("苍老师"))
- .getName();
- }
- }
PS:若想通过代码更好的理解Java8新特性,请:https://github.com/luomingkui/java8