参考:itheima
我的代码:https://gitee.com/machine4869/example-code/tree/master/note_java8new
概述 课程介绍 1 2 3 4 5 Java8(2014年3月发布),更新力度很大,代表性为Lambda(函数式编程) Java9(2017年9月),Jigsaw(模块化) - Lambda表达式、函数式接口(Lamda的基础) - 方法引用、常用函数式接口 - Stream流式处理API、模块化系统(Java9)
Java版本特性更新历史
版本号
年份/代号
新特性(部分举例)
1.0
1996
1.1
1997
JDBC
1.2
1998, Playground
集合、字符串常量池
1.3
2000, Kestrel
性能优化
1.4
2004, Merlin
xml、正则、JDBC3.0、断言(Assert)、NIO
5.0
2004, Tiger
泛型、注解、可变参数、枚举
6.0
2006, Mustang
脚本、JDBC4.0
7.0
2011, Dolphin
NIO.2、try-with-resources
8.0
2014.03
接口更新、Lamda表达式、方法引用、Stream API、函数式接口 、Hashorn、JavaFX、DateTime
9.0
2017.09
Jigsaw(模块化)、JShell、接口小更新
函数式编程思想(Lambda) Lamda表达式 面向对象的Runnable接口写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Demo01Runnable { public static void main (String[] args) { Runnable task = new Runnable() { public void run () { System.out.println("多线程任务执行啦~" ); } }; new Thread(task).start(); } }
编程思想转换,使用Lambda
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class Demo02Lambda { public static void main (String[] args) { new Thread(() -> System.out.println("多线程任务执行啦~" )).start(); } }
带参数和返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Demo05SortLamda { public static void main (String[] args) { Person[] array = { new Person("Tony" , 20 ), new Person("Jay" , 18 ), new Person("Mary" , 19 ) }; System.out.println("排序前:" + Arrays.toString(array)); Arrays.sort(array, (Person p1, Person p2) -> { return p1.getAge() - p2.getAge(); }); System.out.println("排序后:" + Arrays.toString(array)); } }
Lambda表达式的省略格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Demo06LambdaFormat { public static void main (String[] args) { method( (a,b) -> a+b); } public static void method (Calculator calculator) { int result = calculator.sum(111 , 222 ); System.out.println("结果:" +result); } }
Lambda的使用前提
1 2 1. 一个接口,有且仅有一个抽象方法 2. 必须具有上下文环境,才能推导
函数式接口 定义
1 2 3 4 5 6 7 8 9 10 11 12 @FunctionalInterface public interface MyInterface { void method () ; }
使用
1 2 3 4 5 6 7 8 9 public class Demo01FunctionalInterfaceUsage { public static void main (String[] args) { MyInterface myInterface = () -> System.out.println("Lambda表达式" ); myInterface.method(); } }
Lambda与匿名内部类的区别 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Lambda表达式并不是匿名内部类的“语法糖” 语法糖:代码更简洁,但其实原理不变 例如: 1)方法中的可变参数(底层仍然是数组) 2)增强for循环(底层仍然是迭代器) 3)自动装箱\拆箱(底层仍然是new对象) 但是!Lambda表达式和匿名内部类存在根本区别 ------------------------------------------------ 1. 所需类型不同 2. 使用限制不同 Lamda表达式必须要求函数式接口,匿名内部类可以是普通接口、抽象类、普通类 3. 实现原理不同 匿名内部类:其实就是一个类,编译后产生单独的.class文件(XXX$1.class、XXX$2.class) Lamda表达式:编译后没有单独.class文件,对应的字节码会在运行的时候才会动态生成
接口的组成更新 1 2 3 4 5 6 接口组成部分: 1. 常量(public static final) 2. 抽象方法 3. 默认方法(Java 8) 4. 静态方法(Java 8) 5. 私有方法(Java 9)
接口默认方法 定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public interface MyInterface { void method1 () ; void method2 () ; default void methodNew () { System.out.println("接口的默认方法执行" ); } }
MyInterfaceImplA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class MyInterfaceImplA implements MyInterface { @Override public void method1 () { } @Override public void method2 () { } @Override public void methodNew () { System.out.println("可以重写接口的默认方法" ); } }
使用:
1 2 3 4 5 6 7 8 public class Demo01Usage { public static void main (String[] args) { MyInterface objA = new MyInterfaceImplA(); objA.method1(); objA.methodNew(); } }
接口静态方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public interface Animal { void eat () ; static Animal getAnimal () { return new Cat(); } }
1 2 3 4 5 6 7 public class Cat implements Animal { @Override public void eat () { System.out.println("猫吃XX" ); } }
1 2 3 4 5 6 7 8 9 10 11 public class Demo01Animal { public static void main (String[] args) { Animal animal = Animal.getAnimal(); animal.eat(); } }
接口私有方法 是java9引入的,见java9
方法引用 通过方法引用改进代码
常见的方法引用
demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public class Demo01Printer extends PrinterSuper { public static void main (String[] args) { method((s) -> System.out.println(s) , "hello" ); method(System.out::println,"hello" ); StrPrinter sp = new StrPrinter(); method(sp::printStrUper,"hello world" ); method(StrPrinter::staticMethod,"hello" ); Demo01Printer dp = new Demo01Printer(); dp.sayHello(); dp.beHappy(); method(Person::new ,"Tony" ); } public void beHappy () { method( this ::buy,"hello" ); } public void sayHello () { method(super ::fatherMathod ,"hello" ); } public void buy (String str) { System.out.println("本类方法-" +str); } public static void method (Printer printer,String str) { printer.print(str); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package com.mxx.methodref;public class Demo02MethodRefArray { public static void main (String[] args) { method(int []::new ); } private static void method (ArrayBuilder arrayBuilder) { int [] array = arrayBuilder.build(10 ); System.out.println("数组长度为:" +array.length); } }
Lambda的延迟执行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class Demo03Logger { public static void main (String[] args) { String msgA = "hello" ; String msgB = "world" ; String msgC = "java" ; logger(1 ,() -> { System.out.println("lambda执行啦" ); return msgA+msgB+msgC; }); } private static void logger (int level, MsgBuilder msgBuilder) { if (level == 1 ){ System.out.println(msgBuilder.buildMsg()); } } }
使用Lambda作为方法参数/返回值 使用Lambda作为方法参数=使用函数式接口作为参数
1 2 3 4 5 6 method(System.out::println,"hello" ); public static void method (Printer printer,String str) { printer.print(str); }
使用Lambda作为方法返回值=使用函数式接口作为方法返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Demo04LambdaReturn { public static void main (String[] args) { String[] array = {"11" ,"111" ,"1" }; Comparator<String> comp = (s1, s2) -> s1.length() - s2.length(); Arrays.sort(array,comp); System.out.println(Arrays.toString(array)); } }
Lambda使用局部变量的要求 1 2 如果lambda需要使用外部局部变量,局部变量必须是有效final的。(和匿名内部类要求一样) 可以不写final,但该变量不能发生改变
1 2 3 4 5 6 7 8 String msgA = "hello" ; String msgB = "world" ; String msgC = "java" ; logger(1 ,() -> msgA+msgB+msgC);
JDK常用函数式接口 Supplier接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.util.function.Supplier;public class Demo01Supplier { public static void main (String[] args) { method(() -> "hello" ); } private static void method (Supplier<String> supplier) { String str = supplier.get(); System.out.println("内容:" +str); } }
Supplier接口源码
1 2 3 4 5 @FunctionalInterface public interface Supplier <T > { T get () ; }
Consumer接口 接口源码
1 2 3 4 5 6 7 8 9 10 11 12 @FunctionalInterface public interface Consumer <T > { void accept (T t) ; default Consumer<T> andThen (Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
抽象方法使用
1 2 3 4 5 6 7 8 9 10 11 12 import java.util.function.Consumer;public class Demo02Consumer { public static void main (String[] args) { method(System.out::println); } private static void method (Consumer<String> consumer) { consumer.accept("hello" ); } }
默认方法使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java.util.function.Consumer;public class Demo03ConsumerAndThen { public static void main (String[] args) { method((s) -> System.out.println(s.toUpperCase()), (s) -> System.out.println(s.toLowerCase())); } private static void method (Consumer<String> one, Consumer<String> two) { one.andThen(two).accept("Hello" ); } }
Predicate接口 接口源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @FunctionalInterface public interface Predicate <T > { boolean test (T t) ; default Predicate<T> and (Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } default Predicate<T> negate () { return (t) -> !test(t); } default Predicate<T> or (Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } static <T> Predicate<T> isEqual (Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } }
抽象方法使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.util.function.Predicate;public class Demo04Predicate { public static void main (String[] args) { method(s -> s.length() > 10 ); } private static void method (Predicate<String> predicate) { boolean hello = predicate.test("hello" ); System.out.println("判断结果:" +hello); } }
默认方法使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class Demo05PredicateDefault { public static void main (String[] args) { methodAnd(s -> s.contains("H" ), s -> s.contains("w" )); methodOr(s -> s.contains("H" ), s -> s.contains("w" )); methodNegate(s -> s.contains("H" )); } private static void methodAnd (Predicate<String> one, Predicate<String> two) { boolean ret = one.and(two).test("HelloWorld" ); System.out.println("判断结果:" +ret); } private static void methodOr (Predicate<String> one, Predicate<String> two) { boolean ret = one.or(two).test("HelloWorld" ); System.out.println("判断结果:" +ret); } private static void methodNegate (Predicate<String> predicate) { boolean ret = predicate.negate().test("HelloWorld" ); System.out.println("判断结果:" +ret); } }
Function接口 接口源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @FunctionalInterface public interface Function <T , R > { R apply (T t) ; default <V> Function<V, R> compose (Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } default <V> Function<T, V> andThen (Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } static <T> Function<T, T> identity () { return t -> t; } }
抽象方法使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import java.util.function.Function;public class Demo06Function { public static void main (String[] args) { method(Integer::parseInt); } private static void method (Function<String,Integer> function) { int num = function.apply("20" ); num+=30 ; System.out.println("计算结果:" +num); } }
默认方法使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import java.util.function.Function;public class Demo07FunctionDefault { public static void main (String[] args) { methodAndThen(s -> s.split("," )[1 ], Integer::parseInt); methodCompose(s -> s.split("," )[1 ], Integer::parseInt); } private static void methodAndThen (Function<String, String> one, Function<String, Integer> two) { int age = one.andThen(two).apply("大王,20" ); age += 1 ; System.out.println("年龄:" + age); } private static void methodCompose (Function<String, String> one, Function<String, Integer> two) { int age = two.compose(one).apply("大王,20" ); age += 1 ; System.out.println("年龄:" + age); } }
Stream API 概况
1 2 3 java 8中Lambda的衍生物 和IO流无关。IO流:数据流 Stream:跟集合相关,流式处理思想
体验Stream的更优写法 传统集合的多步循环遍历及其弊端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class Demo01Collection { public static void main (String[] args) { List<String> list = new ArrayList<String>(); list.add("赵一" ); list.add("钱一" ); list.add("孙一" ); list.add("李一" ); list.add("张一" ); list.add("张二二" ); list.add("张三二" ); for (String name : list){ if (name != null && name.length() == 3 && name.startsWith("张" )){ System.out.println(name); } } } }
体验Stream的更优写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class Demo03Stream { public static void main (String[] args) { List<String> list = new ArrayList<String>(); list.add("赵一" ); list.add("钱一" ); list.add("孙一" ); list.add("李一" ); list.add("张一" ); list.add("张二二" ); list.add("张三二" ); list.stream() .filter(s -> s.length() ==3 ) .filter(s -> s.startsWith("张" )) .forEach(System.out::println); } }
获取流的多种方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import java.util.stream.IntStream;import java.util.stream.Stream;public class Demo03GetStream { public static void main (String[] args) { Collection<String> collection = new ArrayList<>(); Stream<String> stream1 = collection.stream(); Map<String,Integer> map = new HashMap<>(); Stream<String> streamKey = map.keySet().stream(); Stream<Integer> streamValue = map.values().stream(); Stream<Map.Entry<String, Integer>> streamEntry = map.entrySet().stream(); String[] array = {"王1" ,"王2" ,"王3" }; Stream<String> streamArray = Arrays.stream(array); Stream<String> streamArray2 = Stream.of(array); int [] arrayInt = new int [3 ]; IntStream streamInt = Arrays.stream(arrayInt); } }
Stream的常用方法: 过滤filter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class Demo04StreamFilter { public static void main (String[] args) { List<String> list = new ArrayList<>(); list.add("hello1" ); list.add("world" ); list.add("java" ); Stream<String> stream = list.stream().filter(s -> s.contains("o" )).filter(s -> s.length() == 5 ); } }
统计个数count 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Demo05StreamCount { public static void main (String[] args) { List<String> list = new ArrayList<>(); list.add("hello1" ); list.add("world" ); list.add("java" ); long count = list.stream().filter(s -> s.length() <= 5 ).count(); System.out.println(count); } }
取用前几个limit 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Demo06StreamLimit { public static void main (String[] args) { List<String> list = new ArrayList<>(); for (int i = 0 ; i < 100 ; i++) { list.add("STR-" +i); } list.stream().limit(10 ).forEach(System.out::println); } }
跳过前几个skip 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class Demo05StreamSkip { public static void main (String[] args) { List<String> list = new ArrayList<>(); for (int i = 0 ; i < 100 ; i++) { list.add("STR-" +i); } list.stream().skip(10 ).forEach(System.out::println); } }
映射map 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.mxx.stream;import java.util.ArrayList;import java.util.List;public class Demo08StreamMap { public static void main (String[] args) { List<String> list = new ArrayList<>(); list.add("10" ); list.add("20" ); list.add("30" ); list.stream() .map(Integer::parseInt) .map(i -> i + 1000 ) .forEach(System.out::println); } }
组合concat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.mxx.stream;import java.util.Arrays;import java.util.stream.Stream;public class Demo09StreamContact { public static void main (String[] args) { String[] array1 = {"a" ,"b" ,"c" }; String[] array2 = {"d" ,"e" ,"f" }; Stream<String> stream1 = Arrays.stream(array1); Stream<String> stream2 = Arrays.stream(array2); Stream<String> stream = Stream.concat(stream1, stream2); stream.forEach(System.out::println); } }
逐一消费forEach 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.mxx.stream;import java.util.Arrays;public class Demo10StreamForEach { public static void main (String[] args) { String[] array = {"a" ,"b" ,"c" }; Arrays.stream(array).forEach(System.out::println); Arrays.stream(array).forEach(Demo10StreamForEach::myPrint); } private static void myPrint (String str) { System.out.println("myPrint:" +str); } }
小节:链式方法与终结方法
并发流 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class Demo01ParallelStream { public static void main (String[] args) { List<String> list = new ArrayList<>(); for (int i=0 ;i<100 ;++i){ list.add("STR-" +i); } list.stream().parallel().forEach(System.out::println); } }
收集Stream结果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.util.stream.Collectors;import java.util.stream.Stream;public class Demo01StreamCollect { public static void main (String[] args) { Object[] array = Stream.of("AA" , "BB" , "CC" ).toArray(); String[] array1 = Stream.of("AA" , "BB" , "CC" ).toArray(String[]::new ); List<String> list = Stream.of("AA" , "BB" , "CC" ).collect(Collectors.toList()); Set<String> set = Stream.of("AA" , "BB" , "CC" ).collect(Collectors.toSet()); } }
??Java9 模块化思想 接口组成更新:私有方法