• 零基础学习java------21---------动态代理,java8新特性(lambda, stream,DateApi)


    1. 动态代理

      在一个方法前后加内容,最简单直观的方法就是直接在代码上加内容(如数据库中的事务),但这样写不够灵活,并且代码可维护性差,所以就需要引入动态代理

    1.1 静态代理实现  

      在讲动态代理之前,需要先讲下静态代理,静态代理就是通过proxy持有realObject的引用,并进行一层封装,从而达到增强的效果

    需求:在target中的test方法中加上一些内容(打印结果前后加上日志内容)

    a  简单直观的方法

    接口

    public interface InterfaceA {
        public void test();
    }

    Target类(在上面直接加内容)

    public class Target implements InterfaceA{
        @Override
        public void test() {
            System.out.println("日志开始");   //方法前加内容
            System.out.println("这世界会好吗");
            System.out.println("日志结束");  //方法后加内容
        }
    }

    这样写不够好,破坏了target这个类,万一其他地方需要调用这个方法有的地方需要这内容,有的地方不需要,但又不想要这个日志内容,这样就显得多余了,所以,该怎么解决这个问题呢?

    解决方法:定义一个单独的类来实现这样的需求,这样一个类我们称为代理

    代理类(Proxy)

    public class Proxy implements InterfaceA{
        Target t = new Target();  //目标对象
        @Override
        public void test() {
            System.out.println("日志开始"); //增强
            t.test();
            System.out.println("日至结束");
        }
    }

    测试类

    public class ProxyTest {
        public static void main(String[] args) {
            Proxy p = new Proxy();
            p.test();
        }
    }

    当目标类中的某个方法需要加一些特定的内容(如事务),就可以在代理类中创建目标类的对象并在相应方法加上想要的内容(如事务),在代理类自身的方法内调用相应的方法即可,这样以来就实现了在Target类某个方法灵活加内容的需求,但是其也有一个问题,就是当Target类中有成百上千的方法,并且每个方法都需要加上内容,这时候代理类写起来会很麻烦,这个时候就需要动态代理

    1.2 动态代理的实现

    接口

    1.3 java8新特性

    新特性概览:
      1. 接口中的默认方法与静态方法(即接口中不是只能有抽象方法了)
      2. Lambda 表达式
      3. 集合中的Stream
      4. DateApi
      5. 其他
        String: join
        String str = String.join(",", "a", "b", "c");

    1.3.1. lambda表达式

    1. 使用lambda表达式的前提:

      具有函数式接口(只包含一个抽象方法的接口(SAM),其他实现了的方法可以有多个

    2. 格式: 

      lambda 表达式实际上就是代码块的传递的实现。其语法结构如下:
      (parameters) -> expression 或者(parameters) -> {statements;}

    注意事项:

      a. 括号里的参数可以省略其类型,编译器会根据上下文来推导参数的类型,也可以显式的指定参数类型,如果没有参数,括号内可以为空

      b. 方法体,如果有多行功能语句用大括号括起来,如果只有一行功能语句则可以省略大括号

      c. 可替代匿名内部类

    方法的引用(不太懂):

    方法引用,方法引用是lambda 表达式的一种简写形式。如果lambda 表达式只是调用一个特定的已经存在的方法,则可以使用方法引用。


    使用“::”操作符将方法名和对象或类的名字分隔开来。以下是四种使用情况:
      对象::实例方法
      类::静态方法
      类::实例方法
      类::new

    Arrays.sort(str, (o1,o2)->o1.compareToIgnoreCase(o2));
    Arrays.sort(strings, String::compareToIgnoreCase);

    案例1:以线程为例

    正常开启一个线程的代码如下:

    public class LambdaDemo {
        public static void main(String[] args) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("哈哈");
                }
            }).start();;
        }
    }

    分析:Thread里面一定是runnable对象,所以此可以省略掉,此外,runnable里面只有run方法,所以也可以省略,简化后的代码就变成如下:

    public class LambdaDemo {
        public static void main(String[] args) {
            new Thread(() {     // 此处的小括号不能省略,有可能要传参数
                    System.out.println("哈哈");
            }).start();;
        }
    }

    如果实现的抽象方法只有一行,那么大括号也可以省略,用lambda得到的代码如下

    public class LambdaDemo {
        public static void main(String[] args) {
            new Thread(()-> System.out.println("哈哈")).start();;
        }
    }

    lambda表达式只关注接口中方法的参数,以及方法是怎么实现的

    案例2:list的降序排序

    未使用lambda表达式

    public class LambdaDemo {
        public static void main(String[] args) {
            List<Integer> list = Arrays.asList(1,3,6,12,14,27); 
            Collections.sort(list, new Comparator<Integer>() {  //实现降序排序
                @Override
                public int compare(Integer o1, Integer o2) {
                    // TODO Auto-generated method stub
                    return o2-o1;
                }
            });
        }
    }

    lambda表达式

    public class LambdaDemo {
        public static void main(String[] args) {
            List<Integer> list = Arrays.asList(1,3,6,12,14,27); 
            Collections.sort(list, (o1,o2)-> o2-o1);
        }
      // 遍历此list
      list.forEach((t)->System.out.print(t))
      // 将上面遍历进一步改为方法引用
      list.forEach(System.out::print) }

    此处o1,o2的类型可以省略,如上,编译器会根据上下文自动推断出其类型,此处为Integer类型

    案例3:map的遍历(常规方法有三种,见以前笔记)

    lambda形式

    public class LambdaDemo1 {
        public static void main(String[] args) {
            HashMap<Integer, String> map = new HashMap<>();
            map.put(1, "a");
            map.put(2, "b");
            map.put(3, "c");
            map.put(4, "d");
            map.forEach((k,v)->System.out.println(k+":"+v));
        }
    }

    1.3.2 stream

     Stream是Java 8 提供的高效操作集合类(Collection)数据的API

    1. 如何获取Stream

     (1)使用集合创建

    public static Stream<Integer> getStream() {
        List<Integer> list = Arrays.asList(1,2,3,5,32,24);
        return list.stream();
    }

    (2)使用数组创建

    String[] arr = new String[] {"James","Wade","Kobe","Jardon"};
    return Arrays.stream(arr);

    (3)使用value创建

    return Stream.of("哈哈","呵呵","嘿嘿"); 

    (4)使用iterate创建

    return Stream.iterate("h", n->n+5).limit(10);

    (5)使用generate

    return Stream.generate(Math::random).limit(20);

     2. Stream中常用操作

    (1)forEach:循环输出

    (2)filter:帅选

    (3)limit:限制取多少个

    (4)sorted:

    (5)join:将Stream转成字符串

    public class StreamDemo1 {
        public static void main(String[] args) {
            Stream<String> s4 = Stream.of("I","Love","u");
            String s8 = s4.collect(Collectors.joining(" "));
            System.out.println(s8);//I Love u
            Stream<String> s5 = Stream.of("I","Love","u");
            String s9 = s5.collect(Collectors.joining(",","{","}"));
            System.out.println(s9);//{I,Love,u}
        }
    }

    (6)distinct:去重

    Stream.of("aa","bb","aa").distinct().forEach(System.out::print);//aabb

    (7)map:对每一个元素进行操作

    (8)reduce:归并

    (9)collection:收集(将流转成集合)

    1.3.3DateApi

      jdk8中这个特性使得日期和时间可以分离开(以前的date是连在一起的),其通过三个类实现,如下

    public class DateApiDemo {
        public static void main(String[] args) {
            LocalDateTime now = LocalDateTime.now();//当前时间(日期和时间)
            System.out.println(now); //2019-09-02T16:59:29.862366800
            LocalDate now1 = LocalDate.now();//日期
            System.out.println(now1);//2019-09-02
            LocalTime now2 = LocalTime.now();//时间
            System.out.println(now2);//17:03:32.698811500
        }
    }

    把LocalDateTime转成想要的格式(使用DateTimeFormatter)

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    System.out.println(now.format(dtf)); // 2019-09-02 17:12:36

    把字符串转成LocalDateTime

    LocalDateTime ldt1 = LocalDateTime.parse("2019-09-02 17:12:36",dtf);
    System.out.println(ldt1);//2019-09-02T17:12:36

    此外,此新特性可以得到单独的年,月(中文和英文),日(某个月的第几天,以及某年的第几天)

    System.out.println(now.getYear());//2019    获取年份
    System.out.println(now.getMonth());//SEPTEMBER   获取英文的月份
    System.out.println(now.getMonthValue());//9    获取中文的月数
    System.out.println(now.getDayOfMonth());//2     获取该时间中天数属于该时间的月中的第几天
    System.out.println(now.getDayOfYear());//245    获取该时间中天数属于该时间的年中的第几天

    将确定的时间以单独的年、月、日、小时等来修改来,其形式见下例:

    // 修改年份
    System.out.println(now); // 2019-09-02T19:30:51.234745600
    LocalDateTime d2 = now.withYear(2020);
    System.out.println(d2); // 2020-09-02T19:30:51.234745600
    //修改月份
    LocalDateTime d3 = now.withMonth(11);
    System.out.println(d3); // 2019-11-02T19:30:51.234745600
  • 相关阅读:
    c# ThreadPool 判断子线程全部执行完毕的四种方法
    很多人都爱玩的lol..
    Go 的位操作
    wrk压测工具
    Go函数作为值与类型
    家用PC发展设想
    开车的烦恼
    一款一体机的设想
    nodejs开发环境的搭建
    Python网页抓取程序(续)
  • 原文地址:https://www.cnblogs.com/jj1106/p/11447707.html
Copyright © 2020-2023  润新知