Java8的新特性.pdf

Lambda表达式

适用于比较简单的结构体。避免匿名内部类定义过多的一种函数式编程思想;
接口中只有一个抽象方法,本质就是作为函数式接口的实例

  1. public class test {
  2. public static void main(String[] args) {
  3. new Thread(new Runnable() { //实现匿名内部类
  4. @Override
  5. public void run() {
  6. for(int i=0;i<5;i++) {
  7. System.out.println("a"+i);
  8. }
  9. }
  10. }).start();
  11. for(int i=0;i<5;i++) {
  12. System.out.println("b"+i);
  13. }
  14. }
  15. }
  16. //jdk8 lambda表达式 一般用于比较简单的线程体
  17. public class test {
  18. public static void main(String[] args) {
  19. new Thread(()->{ //关注线程体
  20. for(int i=0;i<5;i++) { //关注内部的核心代码即可 其它的可以简化
  21. System.out.println("a"+i);
  22. }
  23. }
  24. ).start();
  25. for(int i=0;i<5;i++) {
  26. System.out.println("b"+i);
  27. }
  28. }
  29. }

推导过程

  1. interface like{
  2. void lambda();
  3. }
  4. //1 接口实现
  5. class people1 implements like{
  6. @Override
  7. public void lambda() {
  8. System.out.println("快乐");
  9. }
  10. }
  11. public class lambdaTest {
  12. static class people2 implements like{
  13. //2 静态内部类实现
  14. @Override
  15. public void lambda() {
  16. System.out.println("快乐2");
  17. }
  18. }
  19. public static void main(String[] args) {
  20. like l1 = new people1();
  21. like l2 = new people2();
  22. like l3 = new like() {
  23. //3 匿名内部类实现
  24. @Override
  25. public void lambda() {
  26. System.out.println("快乐3");
  27. }
  28. };
  29. like l4 =()->{
  30. //4 lambda表达式实现
  31. System.out.println("快乐4");
  32. };
  33. l1.lambda();
  34. l2.lambda();
  35. l3.lambda();
  36. l4.lambda();
  37. }
  38. }

带参数

  1. interface habb{
  2. void lambda(int a);
  3. }
  4. class people3 implements habb{
  5. @Override
  6. public void lambda(int a) {
  7. }
  8. }
  9. public class lambdatest2 {
  10. public static void main(String[] args) {
  11. habb h1 =(a)->{
  12. System.out.println("快乐"+a);
  13. };
  14. h1.lambda(20);
  15. //简化 只有一个参数 可以省略小括号
  16. habb h2 =a->{
  17. System.out.println("快乐"+a);
  18. };
  19. h2.lambda(30);
  20. //Lambda 体只有一条语句时,return 与大括号若有,都可以省略
  21. habb h3 =a->System.out.println("快乐"+a);
  22. h3.lambda(50);
  23. }
  24. }

函数式接口

如果一个接口中,只声明一个抽象方法,则称为函数式接口
可以在接口上用@FunctionalInterface注解检验声明它是一个函数式接口

Java内置四大核心函数式接口
image.png

  1. public class testFunction {
  2. public static void main(String[] args) {
  3. //消费型接口原始写法
  4. happyTime(500, new Consumer<Double>() {
  5. @Override
  6. public void accept(Double aDouble) {
  7. System.out.println("???"+aDouble);
  8. }
  9. });
  10. //消费型接口lambda写法
  11. happyTime(500, money-> System.out.println("???"+money));
  12. List<String> strings = Arrays.asList("a", "b", "ab", "ac");
  13. filterStrs(strings,s -> s.contains("a")).forEach(System.out::println);
  14. }
  15. //消费型接口
  16. public static void happyTime(double money, Consumer<Double> consumer){
  17. consumer.accept(money);
  18. }
  19. List<String> list = Arrays.asList("a,aa,ab,ac,bc");
  20. List<String> list2 = filterStrs(list, s -> s.contains("c"));
  21. //断定型接口
  22. //根据指定的规则过滤字符串 规则由Predicate 的方法决定
  23. public static List<String> filterStrs(List<String> list, Predicate<String> pre){
  24. ArrayList<String> filterList = new ArrayList<>();
  25. for (String s : list) {
  26. if (pre.test(s)) {
  27. filterList.add(s);
  28. }
  29. }
  30. return filterList;
  31. }
  32. }

方法引用和构造器的引用

方法引用

当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用;
实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的,方法的参数列表和返回值类型保持一致

具体分为如下的三种情况:
对象 :: 非静态方法
类 :: 静态方法
类 :: 非静态方法

  1. public class testFunction2 {
  2. //情况一:对象 :: 实例方法
  3. @Test
  4. public void test1(){
  5. Consumer c1 = str -> System.out.println(str);
  6. c1.accept("hello1");
  7. System.out.println("************");
  8. Consumer c2= System.out::println;
  9. c2.accept("hello2");
  10. }
  11. //Supplier中的T get()
  12. //user中的String getName()
  13. @Test
  14. public void test2() {
  15. user u1 = new user("h", 10000.00);
  16. // 先有对象后再调用
  17. Supplier<String> sup=()->u1.getName();
  18. System.out.println(sup.get());
  19. System.out.println("************");
  20. Supplier<String> sup2=u1::getName;
  21. System.out.println(sup2.get());
  22. }
  23. // 情况二:类 :: 静态方法
  24. //Comparator中的int compare(T t1,T t2)
  25. //Integer中的int compare(T t1,T t2)
  26. @Test
  27. public void test3(){
  28. Comparator<Integer> com1 = (t1, t2) -> Integer.compare(t1,t2);
  29. System.out.println(com1.compare(12,21));
  30. System.out.println("*******************");
  31. Comparator<Integer> com2 = Integer::compare;
  32. System.out.println(com2.compare(12,3));
  33. }
  34. // 情况三:类 :: 实例方法 (前一个参数作为第二个参数的调用者)
  35. // Comparator中的int comapre(T t1,T t2)
  36. // String中的int t1.compareTo(t2)
  37. @Test
  38. public void test4() {
  39. Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);
  40. System.out.println(com1.compare("abc","abd"));
  41. System.out.println("*******************");
  42. Comparator<String> com2 = String :: compareTo;
  43. System.out.println(com2.compare("abd","abm"));
  44. }
  45. //BiPredicate中的boolean test(T t1, T t2);
  46. //String中的boolean t1.equals(t2)
  47. @Test
  48. public void test5() {
  49. BiPredicate<String,String> pre1 = (s1, s2) -> s1.equals(s2);
  50. System.out.println(pre1.test("abc","abc"));
  51. System.out.println("*******************");
  52. BiPredicate<String,String> pre2 = String :: equals;
  53. System.out.println(pre2.test("abc","abd"));
  54. }
  55. }

Stream流

使用 Stream对集合数据进行操作计算,可以执行非常复杂的查找、过滤和映射数据等操作
在Java层面对取到的数据流做处理

注:
Stream 自己不会存储元素
Stream 不会改变源对象。相反,它会返回一个持有结果的新Stream
Stream 操作是延迟执行的。等到需要结果的时候才执行(执行终止操作时才执行中间操作链)

Stream 的操作三个步骤

1 创建 Stream
一个数据源(如:集合、数组),获取一个流
2 中间操作
一个中间操作链,对数据源的数据进行处理
3 终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用

创建

  1. public class streamTest {
  2. public static List<user> getUsers(){
  3. List<user> list = new ArrayList<>();
  4. list.add(new user("h",10000.00));
  5. list.add(new user("h2",10000.00));
  6. list.add(new user("h3",10000.00));
  7. return list;
  8. }
  9. //创建 Stream方式一:通过集合
  10. @Test
  11. public void test1(){
  12. List<user> users =streamTest.getUsers();
  13. // 返回一个顺序流
  14. Stream<user> stream = users.stream();
  15. // 返回一个并行流
  16. Stream<user> parallelStream = users.parallelStream();
  17. }
  18. //创建 Stream方式二:通过数组
  19. @Test
  20. public void test2(){
  21. int[] arr = new int[]{1,2,3,4,5,6};
  22. //调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流
  23. IntStream stream = Arrays.stream(arr);
  24. //自定义类型的数组源
  25. user e1 = new user("m",1000);
  26. user e2 = new user("h",2000);
  27. user[] arr1 = new user[]{e1,e2};
  28. Stream<user> stream1 = Arrays.stream(arr1);
  29. }
  30. //创建 Stream方式三:通过Stream的of()
  31. @Test
  32. public void test3(){
  33. Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
  34. }
  35. //创建 Stream方式四:创建无限流
  36. @Test
  37. public void test4(){
  38. // 迭代
  39. //遍历前10个偶数
  40. Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
  41. // 生成
  42. Stream.generate(Math::random).limit(10).forEach(System.out::println);
  43. Stream.generate(()->random.nextInt(10)).limit(10).forEach(System.out::println);
  44. }
  45. }

中间操作
image.png
image.png
image.png

  1. public static List<user> getUsers(){
  2. List<user> list = new ArrayList<>();
  3. list.add(new user("aaa",10000.00,21));
  4. list.add(new user("bbbb",20000.00,18));
  5. list.add(new user("cc",30000.00,29));
  6. return list;
  7. }
  8. #筛选与切片
  9. @Test
  10. public void test5(){
  11. Stream<user> stream = streamTest.getUsers().stream();
  12. //limit skip distinct 用法差不多
  13. stream.filter(user -> user.getSalary()>10000).forEach(System.out::println);
  14. }
  15. #映射
  16. @Test
  17. public void test6(){
  18. // map(Function f)——接收一个函数作为参数,将元素转换成其他形式或提取信息,
  19. // 该函数会被应用到每个元素上,并将其映射成一个新的元素。
  20. List<String> list = Arrays.asList("aaa", "bb", "cccc", "dd");
  21. //消费型接口
  22. list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
  23. //匹配名字长度大于2的人员
  24. list.stream().map(user::getName).filter(name->name.length()>2).forEach(System.out::println);
  25. // flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
  26. // 类似于list的addAll方法 将多维嵌套的数据转换成单维数据
  27. Stream<Character> characterStream = list.stream().flatMap(streamTest::fromStringToStream);
  28. characterStream.forEach(System.out::println); //获取每个集合中每个字符串的每个字符
  29. }
  30. //将字符串中的多个字符构成的集合转换为对应的Stream的实例
  31. public static Stream<Character> fromStringToStream(String str){
  32. ArrayList<Character> list = new ArrayList<>();
  33. for(Character c : str.toCharArray()){
  34. list.add(c);
  35. }
  36. return list.stream();
  37. }
  38. #排序
  39. @Test
  40. public void test7(){
  41. // sorted()——自然排序
  42. List<Integer> list = Arrays.asList(12, 43, 65, 34, 87, 0, -98, 7);
  43. list.stream().sorted().forEach(System.out::println);
  44. //sorted(Comparator com) -- 定制排序
  45. List<user> users = streamTest.getUsers();
  46. users.stream().sorted( (e1,e2) -> {
  47. int ageValue = Double.compare(e1.getAge(),e2.getAge());
  48. if(ageValue != 0){
  49. return ageValue;
  50. }else{
  51. //年纪相等再比较工资
  52. return -Double.compare(e1.getSalary(),e2.getSalary()); //从大到小排序
  53. }
  54. }).forEach(System.out::println);
  55. }

终止操作
终端操作会从流的流水线生成结果。流进行了终止操作后,不能再次使用。
image.png
image.png
image.png
image.png

  1. //1-匹配与查找
  2. @Test
  3. public void test11(){
  4. List<user> users = streamTest.getUsers();
  5. // allMatch(Predicate p)——检查是否匹配所有元素。
  6. boolean allMatch = users.stream().allMatch(e -> e.getAge() > 18);
  7. System.out.println(allMatch);
  8. // findFirst——返回第一个元素
  9. Optional<user> user = users.stream().findFirst();
  10. System.out.println(user);
  11. }
  12. @Test
  13. public void test12(){
  14. List<user> users = streamTest.getUsers();
  15. // count——返回流中元素的总个数
  16. long count = users.stream().filter(e -> e.getSalary() > 5000).count();
  17. System.out.println(count);
  18. // max(Comparator c)——返回流中最大值
  19. Stream<Double> salaryStream = users.stream().map(e -> e.getSalary());
  20. Optional<Double> maxSalary = salaryStream.max(Double::compare);
  21. System.out.println(maxSalary);
  22. // forEach(Consumer c)——内部迭代
  23. users.stream().forEach(System.out::println);
  24. //使用集合的遍历操作
  25. users.forEach(System.out::println);
  26. }
  27. //2-归约
  28. @Test
  29. public void test13(){
  30. // reduce(T identity, BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回 T
  31. // 计算1-10的自然数的和
  32. List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
  33. Integer sum = list.stream().reduce(0, Integer::sum);
  34. System.out.println(sum);
  35. // reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
  36. // 计算所有员工工资的总和
  37. List<user> users = streamTest.getUsers();
  38. Stream<Double> salaryStream = users.stream().map(user::getSalary);
  39. // Optional<Double> sumMoney = salaryStream.reduce(Double::sum);
  40. Optional<Double> sumMoney = salaryStream.reduce((d1, d2) -> d1 + d2);
  41. System.out.println(sumMoney.get());
  42. }
  43. //3-收集
  44. @Test
  45. public void test14(){
  46. //collect(Collector c)——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
  47. //查找工资大于6000的员工,结果返回为一个List或Set
  48. List<user> users = streamTest.getUsers();
  49. List<user> userList =users.stream()
  50. .filter(e -> e.getSalary()>6000).collect(Collectors.toList());
  51. userList.forEach(System.out::println);
  52. Set<user> userSet = users.stream()
  53. .filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
  54. userSet.forEach(System.out::println);
  55. }
  56. //连接流中每个字符串
  57. list.stream().collect(Collectors.joining()); 等价 String.join("", list)

Optional

是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。

创建Optional类对象的方法:

  • Optional.of(T t) :创建一一个 Optional实例,t必须非空;
  • Optional.empty() :创建一个空 的Optional 实例
  • Optional.ofNullable(T t): t可以为null

判断Optional容器中是否包含对象:
boolean isPresent() :判断是否包含对象
void ifPresent(Consumer<? super T> consumer) :如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。

获取Optional容器的对象:

  • T get():如果调用对象包含值,返回该值,否则抛异常
  • T orElse(T other): 如果有值则将其返回,否则返回指定的other对象。
  • T orElseGet(Supplier<? extends T> other) :如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
  • T orElse Throw(Supplier<? extends X> exceptionSupplier) :如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。
    1. #举例 保证当user为空时不影响下面逻辑代码的执行
    2. User user = null;
    3. User optUser = Optional.ofNullable(user).orElse(new User("a",12));
    4. System.out.println(optUser.getName());