日志 - 4 - @Repository、ssm整合模板、lambda与泛型方法、streamAPI

日志 - 4 - @Repository、ssm整合模板、lambda与泛型方法、streamAPI,第1张

时间:2022年5月21日


上午

首先查询了@Component系列注解,很有印象,这几个注解我只用过@Controller……
参考文章被我放到spring收藏里了。

感觉差不多了之后就尝试写lambda,没想到上来踩了个大坑:lambda不能赋值给泛型方法。

目前正尝试理解lambda不能与泛型方法联动的理由。

@Component系列注解 @Component

因为没有语义,常用来将非controller、service、dao包下的类交给spring,比如pojo、entity。

@Controller

无需多说,老熟人了。

@Service

这个可能要放到实现类(impl)上,反正我xml里配置的是实现类。
________________________________
通过@Autowired注解实现类的mapper属性时,该属性可能会划波浪线,那是因为sprig找不到mapper的实现类。此时,在applictionContext.xml中将它们配置成,其mapper属性也是找不到对象的(赋值一定要用ref而不是value)。
实际上,mapper确实没有实现类,它的接口对应的是mapper.xml。
在applicationContext.xml中配置org.mybatis.spring.mapper.MapperScannerConfigurer的可以让spring找到这些xml文件。

@Repository

注解在dao包的类上。
________________________________
配置了org.mybatis.spring.mapper.MapperScannerConfigurer的后,似乎就用不到这个注解了。

@Mapper

这是mybatis的注解,用来告诉mybatis被它注解的类应该有个mapper.xml。
________________________________
由于是mybatis的注解而不是spring的,这个注解并不能让spring将被它注解的类配置到applicationContext.xml中成为,也就是说,spring不能找到 仅 被@Mapper注解的类。


总之,学到这里就对spring+mybatis有个模板了:

mybatis-config.xml
一、配置,开启日志、二级缓存等。

applicationContext.xml
二、用载入database.properties。
三、配置datasource的
四、配置SqlSessionFactoryBean的,传入datasource和configLocation(mybatis-condif.xml)
五、配置MapperScannerConfigurer的,传入SqlSessionFactoryBean和放置mapper的包。

applicationContext.xml
六、开,传入被扫描的包(多个包则开多个)
七、controller与service包中使用相关注解。

顺便把spring+springmvc也写在这里:

applicationContext.xml
一、开,和不是一个东西。
二、开,用于阻止spring的DispatcherServlet拦截前端对css、js、img等静态资源的请求。
三、配置org.springframework.web.servlet.view.InternalResourceViewResolver的,spring的视图解析器(话说这东西必须得配置吗?

web.xml
四、配置org.springframework.web.servlet.DispatcherServlet,传入applicationContext.xml。
五、配置org.springframework.web.filter.CharacterEncodingFilter,传入字符集名(是spring用于转换前后端字符集的内置filter)。

啊,浑身清爽 ~ ~

springboot+各种东西,这点还不太熟悉。

欠缺的部分:事务、spring中开启mapperscan后是否还要把mapper.xml配置给mybatis、


下午

看见 官方文档(英文)说lambda不支持泛型方法后,我就立马放弃了。不过好歹也算是为它烦恼了一个小时的,不留点记录怎么能行呢?

官方文档上记载了lambda不支持泛型方法,知道这件事是从别的文章上,不过文章有些短,就直接把官方文档搬过来了。

文档上说lambda不适应拥有类型参数(type parameter)的方法,那么什么是类型参数呢?

E get(E e);

这个 E 就是类型参数,“” 是在定义 E 这个类型参数。

已经很明显了,泛型就是通过类型参数(type parameter)来定义的,lambda不适应携带类型参数的方法,就是在直言无法支持泛型方法。

为什么呢?我的理解是这样的:

在泛型方法中定义的类型参数(E)只能在这个泛型方法中使用,脱离了这个泛型方法就再也没办法获取这个类型参数了。
而lambda本身就是为了在方法之外 “定义” 方法,既然已经身置泛型方法之外了,那就无论如何都不可能使用 E 这个类型了,就算再定义一个 E,此 E 非彼 E 也是不能用的。

干嘛非得使用泛型方法里的 E 呢?
你想啊,lambda是在干什么?是在重写函数式接口的唯一抽象方法。
那重写方法有什么条件?参数列表完全一致,返回值一致,方法名一致。
参数列表完全一致,这就要求你lambda必须用我泛型方法里定义的这个 E,而不是你自己定义的什么 T、V、K。哪怕你定义了一个 E,那也不是我泛型方法里的 E,和我的参数列表不一致,就不算重写我的方法。

lambda:你还想要我怎样???毁灭吧!

不过在 玩耍 debug 的过程中倒是发现了另外一件有趣的事情,双冒号表达式是可以支持泛型方法的……

不想了不想了,pass。

接下来是双冒号表达式 “MyClass::instance_method” 用法的使用条件:

一、抽象方法的参数必须比实例方法(instance_method)的参数多一个
二、多出来的这个参数必须是class类型的
三、多出来的这个参数必须在参数列表的首位(最左侧)。


接下来是我已经期待了两天的时刻:把lambda常见的应用场景收集起来!

话虽如此,但也就找到两条,其中一条算不算常用还很难说…( _ _)ノ|

lambda的不常用场景

new Thread(Runnable),创建一个线程,定义线程执行的代码。
JButten_instance.addActionListener(ActionListener),给jbutton上监控,定义监控的执行代码。

java.util.stream.Stream

这里有一篇 已经把stream解释得很清晰的文章,就是有点长,好在可以根据目录直接定位到stream那一段。
这里有另一篇 也很详细地讲解了stream的文章(简书),就是有点多,好在也有目录(doge)

三个特征:
一、若不进行终端 *** 作,所有代码都 不执行。
二、用了终端 *** 作之后,这个流就 不能用了(可以保存成集合或数组,从而反复使用,缺点是每次使用都得再封装成流)。
三、流不是集合,对流进行 *** 作不是在对集合进行 *** 作,无论如何都不会改变集合中的元素。

基本数据类型流:IntStream、LongStream、DoubleStream
>>> toArray(),返回(拆封为)基本数据类型数组
>>> boxed(),转换为 包装类对象流。
>>> 内置sum()、average()、max()、min()
>>> Random_instance.ints(size, origin, bound),返回一个 IntStream 实例,其中size为元素数目,origin为最小值,bound为最大值,且左闭右开。(同样地,可以使用doubles(),longs())。
>>> IntStream.range(start, end),返回一个IntStream实例,其中start为最小值,end为最大值,步长默认为1,左闭右开(DoubleStream没有这个静态方法。rangeClosed()可以包含右边界)
________________________________
基本数据类型流的collect()无法通过collectors.toList()将它们封装成集合(没有这种重载),因为基本数据类型本来就没办法直接放到集合里。

串行流(sequential())、并行流(parallel())、无序流(unordered())
这方面有点模糊,可能是我还没有看到描述得很清晰的文档,目前对它们的了解仅限于:一个线程、多个线程、破坏有序集合的顺序。
至于list.stream()究竟到手那种流……可能 是串行流?
________________________________
对无序流有点在意,因为 javadoc 说对于[2,4,6]形成的集合,无序流模式下计算map(a->a*2)可能给出[12,4,8]这种结果,所以给它排序是很重要的,除非根本不在意它的顺序(这种场景还是蛮多的)。

创建(包装为)stream

list.stream(),从集合实例中获取流对象(以下简称 “流”)
list.parallelStream(),从集合中获取并行流(另外两种流通过流对象转换)

Arrays.stream(T[]),通过 T 数组构建一个流(有入参为int[]、long[]、double[]的重载方法,分别获取IntStream、LongStream、DoubleStream)

Stream.of(T…),用一串元素构成流(类似Arrays.asList())

Stream.Iterate(T, UnaryOperator),迭代计算一个初始值,以每次得到的结果作为元素形成流(需要用 limit() 约束其迭代次数,否则它就是一个无限流,可能会被其他流 *** 作截断为有限流)
Stream.generate(supplier),根据被定义的供给者(supplier)获取数个元素,形成流(同上,以 limit() 约束)

流 *** 作(中间 *** 作)

limit(long),仅保留流中前n个元素(如果是无序流,因为流是无序的,所以不知道究竟保留了哪些元素)
filter(predicate),筛选元素(保留使predicate.test()返回true的)。
distinct(),去重。
skip(long),跳过前n个元素。
________________________________
这该死的 sql 既视感(笑死

map(Function),按照Function的 “定义” 计算每一个元素,其结果映射为新的流(能用来获取对象属性,简直神迹)
mapToXXX(ToXXXFunction),映射为 基本数据流(XXX为:Int、Long、Double)。
flatMap(Function),将每个元素转换为流,最后合并成一个大流(同样,有int、long、double适用的方法)。
________________________________
不能和下面的 reduce()放到一起还蛮可惜的,这回是hadoop既视感(笑死,我大数据还没入门

sorted(),按照默认规则排序
sorted(Comparator),传入一个比较器(函数式接口)

终端 *** 作(用了就会把流 消耗掉 的 *** 作)

reduce(T, BinaryOperator),根据二元算子(BinaryOperator)的 “定义” 进行迭代计算,得到一个 T 类型的返回值(参数 T 参与第一次迭代)。
reduce(BinaryOperator),流中第一个元素与第二个元素进行第一次迭代,直至得到最终结果。
________________________________
迭代:每次计算的结果作为下一次计算的参数之一。
此方法不会影响流中元素,仅返回计算结果。

XXXMatch(predicate),对每个元素进行测试(XXX:all,要求全部为true;any:任意一个为true;none,不能有true)
findXXX(),获取一个元素(XXX:First,流中第一个;Any,任意一个)

max(Comparator),传入比较器,返回最大值
min(Comparator),传入比较器,返回最小值

count(),返回元素总数(类似数组的 length,集合的 size())
foreach(Consumer),对流中每个元素做些什么 ,但是禁止色色,另一件神器。
collect(Collector),返回(拆封成)一个集合(一般Collectors的方法获取实参,Collectors 不是 Collector的实现类)
toArray(IntFunction),返回(拆封成)一个数组(传入Integer::new这种形式,任何可以与流中元素进行转换的类都可以(自定义类也可以),但不能是基本数据类型。个人认为用到了代理?总之不必深究)

Collectors(很多方法没放到这里)

toList(),让collect()返回List集合。
toSet(),让collect()返回Set集合。

我是真没想到一写就写了一下午,关键是文章还没看完……

此处 并没有 把Stream的所有方法枚举 把别人文章上的方法都搬过来了倒是真的。

后记

有种整个下午都写跑题了的感觉,不过学了stream发现这东西是真好用。

遗留:

收集日常可以用到lambda的方法(怨气……了解spring事务相关的部分(怨气*2……

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1294766.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-10
下一篇 2022-06-10

发表评论

登录后才能评论

评论列表(0条)

保存