前面介绍了Commons Logging和Log4j这一对好基友,它们一个负责充当日志API,一个负责实现日志底层,搭配使用非常便于开发。
为什么要使用s l f4j
我们自己的系统中使用了logback这个日志系统
我们的系统使用了A.jar,A.jar中使用的日志系统为log4j
我们的系统又使用了B.jar,B.jar中使用的日志系统为slf4j-simple
这样,我们的系统就不得不同时支持并维护logback、log4j、slf4j-simple三种日志框架,非常不便。
解决这个问题的方式就是引入一个适配层,由适配层决定使用哪一种日志系统,而调用端只需要做的事情就是打印日志而不需要关心如何打印日志,slf4j或者commons-logging就是这种适配层,slf4j是本文研究的对象。
从上面的描述,我们必须清楚地知道一点:slf4j只是一个日志标准,并不是日志系统的具体实现。理解这句话非常重要,slf4j只做两件事情:
- 提供日志接口
- 提供获取具体日志对象的方法
1 | #下面是配置将日志信息插入数据库, |
1 | 同义词在去重校验逻辑中的业务编码为2 |
@Query注解:
这种查询可以声明在 Repository 方法中,摆脱像命名查询那样的约束,将查询直接在相应的接口方法中声明,结构更为清晰,这是 Spring data 的特有实现。
如果是 @Query 中有 LIKE 关键字,后面的参数需要前面或者后面加 %,这样在传递参数值的时候就可以不加 %
还可以使用@Query来指定本地查询,只要设置nativeQuery为true,
简明扼要的介绍一下@Data注解的功能与使用方法
注解功能
1、@Data可以为类提供读写功能,从而不用写get、set方法。
2、@Data提供 equals()、hashCode()、toString() 方法。
Lombok项目是一种自动接通你的编辑器和构建工具的一个Java库。不用再一次写额外的getter或者equals方法。由此可以看出,lombok会帮我们自动生成getter和euqals方法,但是更有意思的是,当我们的变量发生改变时,我们不再需要修改对的getter、setter方法,lombok帮我们在运行的过程中自动生成上述方法,编码更灵活.
所以,使用lombok的优点: 1、简化long冗余的javabean代码;
2、提高执行效率
lombok中的常用注解
- @Setter :在JavaBean或类JavaBean中使用,使用此注解会生成对应的setter方法;
- @Getter:在JavaBean或类JavaBean中使用,使用此注解会生成对应的getter方法;
- @ToString:在JavaBean或类JavaBean中使用,使用此注解会自动重写对应的toStirng方法;
- @NoArgsConstructor:在JavaBean或类JavaBean中使用,使用此注解会生成对应的无参构造方法;
- @HashCode:
- @Equals:
- @CanEqual:
- @Data:在JavaBean或类JavaBean中使用,这个注解包含范围最广,它包含上述注解,即当使用当前注解时,会自动生成包含的所有方法;
- @AllArgsConstructor:在JavaBean或类JavaBean中使用,使用此注解会生成对应的有参构造方法;
- @Log(这是一个泛型注解,具体有很多种形式)
- @EqualsAndHashCode:在JavaBean或类JavaBean中使用,使用此注解会自动重写对应的equals方法和hashCode方法;
- 此注解会生成
equals(Object other)
和hashCode()
方法。 - 它默认使用非静态,非瞬态的属性
- 可通过参数
exclude
排除一些属性 - 可通过参数
of
指定仅使用哪些属性 - 它默认仅使用该类中定义的属性且不调用父类的方法
- 可通过
callSuper=true
解决上一点问题。让其生成的方法中调用父类的方法。 - @Slf4j:在需要打印日志的类中使用,当项目中使用了slf4j打印日志框架时使用该注解,会简化日志的打印流程,只需调用info方法即可;
@ToString(exclude=”column”)
意义:排除column列所对应的元素,即在生成toString方法时不包含column参数;
@ToString(exclude={“column1”,”column2”})
意义:排除多个column列所对应的元素,其中间用英文状态下的逗号进行分割,即在生成toString方法时不包含多个column参数;
@ToString(of=”column”)
意义:只生成包含column列所对应的元素的参数的toString方法,即在生成toString方法时只包含column参数;;
@ToString(of={“column1”,”column2”})
意义:只生成包含多个column列所对应的元素的参数的toString方法,其中间用英文状态下的逗号进行分割,即在生成toString方法时只包含多个column参数;
Java中的::是Java8的新特性的应用。
foreach是属于Java集合的一个方法,准确来说,集合中Java8拥有一个stream方法,可以得到一个流对象,这个对象拥有很多方法,这些方法可以很方便的对集合进行例如排序,分组,计数,遍历,转换等操作,而遍历是比较常见的一种,forEach就是用来做这个的,这里的forEach就是stream的forEach。
java此时还有另外一个特性叫做lambda表达式和函数式接口,仅仅有一个未实现方法的接口,可以直接写作**(参数列表)** -> {方法体}这种形式。
省去了之前需要专为他编写一个实现类或者匿名内部类的代码,直接对接口进行实现。
forEach方法提供一个某种类型的Object,(具体是什么类型是要看Stream类的泛型参数
而System.out.println可以接受一个Object,因此,forEach提供的参数和System.out.println的参数类型是一致的,可以进行这种简写。
具体来说就是:原本应该写为:
.forEach(element -> {
System.out.println(element)
})
但是System.out.println的参数和传递的参数element 的类型完全匹配,所以这样的时候就可以简化为:
.forEach(System.out::println)
即forEach将会使用System.out对象的println方法进行接下来的操作。
1 | List<String> list = new ArrayList<>(); |
其中list.forEach可以改写成以下代码:
1 | for(int i = 0; i < list.size(); i++) { |
或者等于以下代码:
1 | for(String s : list) { |
实际场景
有一个集合:List users = getList(); //从数据库查询的用户集合
现在想获取User的身份证号码;在后续的逻辑处理中要用,
常用的方法我们大家都知道,用for循环,
1 | List idcards=new ArrayList();//定义一个集合来装身份证号码 |
这种方法要写好几行代码,有没有简单点的,有,java8 API能一行搞定:
1 | List idcards= users.stream().map(User::getIdcard).collect(Collectors.toList()); |
Arrays.stream()
为什么需要 Stream
Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。
Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。
通常编写并行代码很难而且容易出错,但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。所以说,Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。
什么是流
Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;
高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。
Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。
而和迭代器又不同的是,Stream 可以并行化操作,迭代器只能命令式地、串行化操作。顾名思义,当使用串行方式去遍历时,每个 item 读完后再读下一个 item。而使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。
Java 的并行 API 演变历程基本如下:
- 1.0-1.4 中的 java.lang.Thread
- 5.0 中的 java.util.concurrent
- 6.0 中的 Phasers 等
- 7.0 中的 Fork/Join 框架
- 8.0 中的 Lambda