JAVA8-lambda表达式8:在设计模式-模板方法中的应用
传送门
JAVA8-lambda表达式1:什么是lambda表达式
JAVA8-lambda表达式2:常用的集合类api
JAVA8-lambda表达式3:并行流,提升效率的利器?
JAVA8-lambda表达式4:Optional用法
java8-lambda表达式5:toMap引发的线上故障
JAVA8-lambda表达式6:重构和定制收集器
JAVA8-lambda表达式7:重要的函数接口
如何看待写代码这件事
最近在公司写代码(包括看代码),突然有一点小小的感叹。好多人整天研究什么高并发,高可用,分布式,开口架构闭口新技术,就是不愿意花时间把自己的JAVA代码写的好一点。
把代码写好就是给自己印的最好的名片,也是对同事最大的负责!
可惜好多人不这样认为,或者说可能是现在环境就是这样吧:面试各种的造火箭,考算法导致从业者只能投其所好,刷题/刷各种高大上的所谓架构技术,而忽视一个最本质的前提!
那就是技术是为业务服务的,绝大部分的公司是用不上所谓的大厂架构的,强行匹配只会适得其反。
有空还是多琢磨琢磨怎么把那点JAVA代码写的更好吧。
这里的说法有点属于"夹带私货"了,太过片面了,切勿对号入座。
什么是模板方法
在很早以前(真的是很早了,看了下发布日期是2018年2月!),学习过模板方法,它属于常用的设计中的一种。当时里面介绍的例子取自《Head First设计模式》,所以文章算作是翻译过来的。例子比较简单,实现也是用的继承+多态的。而还有一种很常用的模板方法,就是一个类+静态方法,使用者直接通过静态方法来调用!
Template.execute(a,b);
- Template为类名
- execute为方法
- a,b为参数
在上面的调用中,Template.execute是不会变化,顾名思义就是模板方法的意思。而a,b则是需要调用方传递的参数,必须是模板规定的类型。下面就以一个实际场景来看看如何抽象一个模板方法。
接口调用场景
对于JAVA程序员来说,spring肯定绕不开的结。当需要写一个后端接口的时候,通过springMVC可以很方便的来实现,比如在Oauth2系列7:授权码和访问令牌的颁发流程是怎样实现的?里面提到的准备工作-验证基本信息:
@RestController
@RequestMapping("/auth")
public class OauthController
{@GetMapping("/authorize")public void authorize(@RequestParam("response_type") String responseType, @RequestParam("client_id") String clientId,@RequestParam("redirect_uri") String redirectUri, String scope){}
}
还有验证客户端-生成访问令牌:
@PostMapping("/token")public TokenModel getToken(@RequestBody GetTokenRequest getTokenRequest) {// 获取令牌前置检验preGetTokenCheck(getTokenRequest);// 检验授权码checkCode(getTokenRequest.getCode());// 生成t访问令牌TokenModel tokenModel = generateToken();return tokenModel;}
private TokenModel generateToken() {// 获取code信息,比如从redis// CodeModel codeModel = getCode;TokenModel tokenModel = new TokenModel();tokenModel.setAccessToken(UUID.randomUUID().toString());tokenModel.setExpiresIn(3600);tokenModel.setRefreshToken(UUID.randomUUID().toString());// tokenModel.setScope(codeModel.getScope);return tokenModel;}
- 在类上打上注解RestController或Controller,现在一般自动转换json就用RestController
- 在方法上打上注解RequestMapping或GetMapping/PostMapping等,表示这个是一个接口方法
- 在方法里面打上注解RequestParam或PathVariable,用来获取参数
大致按照这3个步骤来操作,剩下的主要就是业务代码编写了(实际项目里面也没有什么大的区别)。一般项目会分层,简单的就三层:Web/Service/Dao。
- Web表示展示层:接口的入参获取,参数检验;日志打印;响应转换/返回(包括异常处理)
- Service就是业务层:处理业务逻辑的,是方法的主体代码
- Dao层称为存储层:一般表示db处理,也可以是其它持久操作
模板方法
根据上面简单三层的理解,定义一个模板方法出来:
@Slf4j
public class WebTemplate
{public static String execute(String req){try{// 1:打印入参log.info("方法参数:{}", req);// 2:参数检验// TODO// 3:业务方法}catch (Exception e){// 4:异常处理return "fail";}return "success";}
}
这里定义了模板方法的步骤:
- 入参类型(如果是上面的例子只能的String肯定有局限性),最好支持泛型,比如都继承Request基类
- 参数打印:将参数都打印出来,方便统计排查
- 参数检验:对输入参数进行检验,如果不符合条件则抛出异常,让步骤4异常来统一处理
- 业务方法执行:对于这种业务方法的执行,可以定义一个接口让调用方来实现
- 异常执行:异常可以分为业务/全局异常,进行统一的处理,直接抛出或转换成对应异常码
- 组装响应:响应可以自定义,比如如上的异常码/异常信息
- 后置处理:可以在方法结束时,进行需要的后置处理,比如打印日志,方便后续监控
由此可见一个完整模板方法类似如下:
package com.tw.tsm.base.template;import com.tw.tsm.base.request.BaseRequestDTO;
import com.tw.tsm.base.response.BaseResponseDTO;
import lombok.extern.slf4j.Slf4j;/*** 模板方法类*/
@Slf4j
public class WebTemplate
{/*** 模板方法* @param req 请求参数* @param res 响应参数* @param callback 回调方法* @param <T>* @param <R>*/public static <T extends BaseRequestDTO, R extends BaseResponseDTO> void execute(T req, R res, ServiceCallback callback){try{// 1:打印入参log.info("方法参数:{}", req);// 2:参数检验callback.check(req);// 3:业务方法callback.doService(req);}catch (Exception e){// 4:异常处理}finally{log.info("处理结果:{}", res);}}
}/*** 请求基类*/
public class BaseRequestDTO
{
}/*** 响应基类*/
@Data
public class BaseResponseDTO<T>
{/** 错误码 */private String code;/** 错误信息 */private String msg;/** 返回内容 */private T data;
}/*** 模板处理接口* * @param <T>*/
public interface ServiceCallback<T>
{void check(T req);void doService(T req);
}
至此,模板方法已经初具雏形,对于调用方来说,即可如下:
WebTemplate.execute(req, new BaseResponseDTO(), new ServiceCallback() {@Overridepublic void check(Object req) {// 参数检验}@Overridepublic void doService(Object req) {// 业务方法}});
lambda在模板方法中的应用
既然是要用lambda表达式在模板方法中应用,所以就不能像刚才那样对于回调函数直接用匿名类,这里就改造一下:
/*** 模板回调函数* * @param <T>*/
@FunctionalInterface
public interface ServiceCallback<T>
{default void check(T req){}void doService(T req);
}WebTemplate.execute(req, new BaseResponseDTO(), request -> {});
- 首先改造一下回调函数,增加@FunctionalInterface注解,表示这是一个函数式接口
- 将chec()方法声明为default,这里java8的默认方法
- 最近用lambda实现业务处理逻辑
相关文章:
JAVA8-lambda表达式8:在设计模式-模板方法中的应用
传送门 JAVA8-lambda表达式1:什么是lambda表达式 JAVA8-lambda表达式2:常用的集合类api JAVA8-lambda表达式3:并行流,提升效率的利器? JAVA8-lambda表达式4:Optional用法 java8-lambda表达式5…...
React之组件间通信
React之组件间通信 组件通信: 简单讲就是组件之间的传值,包括state、函数等 1、父子组件通信 父组件给子组件传值 核心:1、自定义属性;2、props 父组件中: 自定义属性传值 import Header from /components/Headerconst Home ()…...
【MATLAB第58期】基于MATLAB的PCA-Kmeans、PCA-LVQ与BP神经网络分类预测模型对比
【MATLAB第58期】基于MATLAB的PCA-Kmeans、PCA-LVQ与BP神经网络分类预测模型对比 一、数据介绍 基于UCI葡萄酒数据集进行葡萄酒分类及产地预测 共包含178组样本数据,来源于三个葡萄酒产地,每组数据包含产地标签及13种化学元素含量,即已知类…...
CF1833 A-E
A题 题目链接:https://codeforces.com/problemset/problem/1833/A 基本思路:for循环遍历字符串s,依次截取字符串s的子串str,并保存到集合中,最后输出集合内元素的数目即可 AC代码: #include <iostrea…...
【深度学习】【Image Inpainting】Generative Image Inpainting with Contextual Attention
Generative Image Inpainting with Contextual Attention DeepFillv1 (CVPR’2018) 论文:https://arxiv.org/abs/1801.07892 论文代码:https://github.com/JiahuiYu/generative_inpainting 论文摘录 文章目录 效果一览摘要介绍论文贡献相关工作Image…...
二维深度卷积网络模型下的轴承故障诊断
1.数据集 使用凯斯西储大学轴承数据集,一共有4种负载下采集的数据,每种负载下有10种 故障状态:三种不同尺寸下的内圈故障、三种不同尺寸下的外圈故障、三种不同尺寸下的滚动体故障和一种正常状态 2.模型(二维CNN) 使…...
redis突然变慢问题定位
CPU 相关:使用复杂度过高命令、O(N)的这个N,数据的持久化,都与耗费过多的 CPU 资源有关 内存相关:bigkey 内存的申请和释放、数据过期、数据淘汰、碎片整理、内存大页、内存写时复制都与内存息息相关 磁盘…...
React井字棋游戏官方示例
在本篇技术博客中,我们将介绍一个React官方示例:井字棋游戏。我们将逐步讲解代码实现,包括游戏的组件结构、状态管理、胜者判定以及历史记录功能。让我们一起开始吧! 项目概览 在这个井字棋游戏中,我们有以下组件&am…...
七大经典比较排序算法
1. 插入排序 (⭐️⭐️) 🌟 思想: 直接插入排序是一种简单的插入排序法,思想是是把待排序的数据按照下标从小到大,依次插入到一个已经排好的序列中,直至全部插入,得到一个新的有序序列。例如:…...
【点云处理教程】03使用 Python 实现地面检测
一、说明 这是我的“点云处理”教程的第3篇文章。“点云处理”教程对初学者友好,我们将在其中简单地介绍从数据准备到数据分割和分类的点云处理管道。 在上一教程中,我们在不使用 Open3D 库的情况下从深度数据计算点云。在本教程中,我们将首先…...
Python 日志记录:6大日志记录库的比较
Python 日志记录:6大日志记录库的比较 文章目录 Python 日志记录:6大日志记录库的比较前言一些日志框架建议1. logging - 内置的标准日志模块默认日志记录器自定义日志记录器生成结构化日志 2. Loguru - 最流行的Python第三方日志框架默认日志记录器自定…...
最近遇到一些问题的解决方案
最近遇到一些问题的解决方案 SpringBoot前后端分离参数传递方式总结Java8版本特性讲解idea使用git更新代码 : update project removeAll引发得java.lang.UnsupportedOperationException异常Java的split()函数用多个不同符号分割 Aspect注解切面demo 抽取公共组件,使…...
封装hutool工具生成JWT token
private static final String KEY "abcdef";/*** 生成token** param payload 可以存放用户的一些信息,不要存放敏感字段* return*/public static String createToken(Map<String, Object> payload) {//十分重要,不禁用发布到生产环境无…...
【手机】三星手机刷机解决SecSetupWizard已停止
三星手机恢复出厂设置之后,出现SecSetupWizard已停止的解决方案 零、问题 我手上有一部同学给的三星 GT-S6812I,这几天搞了张新卡,多余出的卡就放到这个手机上玩去了。因为是获取了root权限的(直接使用KingRoot就可以࿰…...
GDAL C++ API 学习之路 OGRGeometry 抽象曲线基类 OGRCurve
OGRCurve class "ogrsf_frmts.h" OGRCurve 是 OGR(OpenGIS Simple Features Reference Implementation)几何库中的一个基类,表示曲线几何对象。它是 OGRLineString 和 OGRCircularString 的抽象基类,用于表示曲…...
etcd底层支持的数据库有哪些
etcd底层的数据库可以更换。在当前版本的etcd中,它使用的是BoltDB作为默认的后端存储引擎。但是,etcd提供了接口允许您更换数据库后端,以便根据需要选择更合适的存储引擎。 以下是etcd支持的一些后端数据库选项: BoltDBÿ…...
linux设备驱动的poll与fasync
什么是fasync 在 Linux 驱动程序中,fasync 是一种机制,用于在异步事件发生时通知进程。它允许进程在等待设备事件时,不必像传统的轮询方式那样持续地查询设备状态。 具体来说,当进程调用 fcntl(fd, F_SETFL, O_ASYNC) 函数时&am…...
TortoiseGit安装与配置
注:在安装TortoiseGit之前我已经安装了git工具。 二、Git的诞生及环境配置_tortoisegit安装包_朱嘉鼎的博客-CSDN博客 1、TortoiseGit简介 TortoiseGit是基于TortoiseSVN的Git版本的Windows Shell界面。它是开源的,可以完全免费使用。 TortoiseGit 支持…...
Java代码打印空心菱形(小练习)
回看基础 利用Java代码打印一个空心菱形 //5. 打印空心菱形 import java.util.Scanner; public class MulForExercise01 {//编写一个 main 方法public static void main(String[] args) {Scanner myScanner new Scanner(System.in);System.out.println("请输入正三角的行…...
【性能优化】MySQL百万数据深度分页优化思路分析
业务场景 一般在项目开发中会有很多的统计数据需要进行上报分析,一般在分析过后会在后台展示出来给运营和产品进行分页查看,最常见的一种就是根据日期进行筛选。这种统计数据随着时间的推移数据量会慢慢的变大,达到百万、千万条数据只是时间问…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...
Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
2025年低延迟业务DDoS防护全攻略:高可用架构与实战方案
一、延迟敏感行业面临的DDoS攻击新挑战 2025年,金融交易、实时竞技游戏、工业物联网等低延迟业务成为DDoS攻击的首要目标。攻击呈现三大特征: AI驱动的自适应攻击:攻击流量模拟真实用户行为,差异率低至0.5%,传统规则引…...
