Gradle接入checkstyle代码风格检查插件

news2024/11/18 18:46:52

一、什么是checkstyle

在项目开发的过程中,代码规范是经常被提起的话题,特别是当项目需要多个开发协同完成的时候,良好统一的代码规范能够在一定程度上保证项目代码的质量和团队的开发效率。目前业界常见代码检查工具有 Alibaba Java Coding Guidelines,Sonar,checkstyle 等,前两者更多是道德层面的约束,需要依靠自觉自检,而 checkstyle 则可以强制统一开发团队的代码风格和规范。

毕竟在团队开发过程中,每个人都有自己的代码风格,统一代码风格有助于提高代码的可维护性和可读性,也可以减少在 CodeReview 过程中的争议。

二、主要用途

Checkstyle 可以通过定义一系列规则和规范来检查代码,例如缩进、命名约定、代码注释、代码布局等。通过强制执行这些规则,可以确保整个团队编写的代码具有一致的风格,使代码更易于阅读、理解和维护。如果只是把 checkstyle 当作代码风格检查工具,那就有点委屈了它。除了代码风格的统一外,还可以自动化代码审查,可以自动检测代码中的潜在问题和错误,如未使用的变量、未处理的异常、错误的代码格式等,以便在开发阶段变能发现潜在的问题。

同时,checkstyle 能提高代码质量,通过强制执行代码规范和规则,促使开发人员编写更高质量的代码。它可以防止一些常见的编码错误,提高代码一致性和可读性,减少代码维护的成本。同时 checkstyle 提供了灵活的配置选项,允许根据项目的需求自定义规则集,也许一开始使用的时候可能会不习惯,但是用了一段时间回头看整体的代码,就会有赏心悦目的感觉,仿佛在看一件艺术品。

三、插件集成

我们的项目采用的是 Gradle 进行构建,所以本文介绍 Gradle 下 checkstyle 插件的集成,整体集成并不复杂,Maven 也是类似的操作,操作步骤也可以参考 Gradle官网。

在 Gradle 官网上可以看到关于 checkstyle 推荐的目录结构如下:

在这里插入图片描述

在根目录下新建 config 目录用来存放 checkstyle 的文件,这里需要准备两个文件,分别是 checkstyle.xml 和 suppressions.xml。前者是用来配置代码检查的规则,后者可以配置忽略检查的一些文件。配置文件可以直接使用谷歌的校验规则 checkstyle.xml,但是整体规则比较严格,这里提供自定义的校验规则模版,可以作为参考:

checkstyle.xml:

<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
        "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
        "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">

<module name="Checker">

    <property name="charset" value="UTF-8"/>
    <property name="severity" value="error"/>
    <property name="fileExtensions" value="java, properties"/>

    <module name="SuppressionFilter">
        <property name="file" value="config/checkstyle/suppressions.xml"/>
    </module>

    <module name="Header">
        <!-- 指定要处理的文件的文件类型扩展名为java -->
        <property name="fileExtensions" value="java"/>
    </module>

    <!--To configure the check to report on the first instance in each file-->
    <!--<module name="FileTabCharacter"/>-->

    <!-- 文件长度不超过1500行 -->
    <module name="FileLength">
        <property name="max" value="1500"/>
    </module>

    <!-- 每个java文件一个语法树 -->
    <module name="TreeWalker">
        <!-- import检查-->
        <!-- 避免使用* -->
        <module name="AvoidStarImport"/>
        <!-- 检查是否从非法的包中导入了类 -->
        <module name="IllegalImport"/>
        <!-- 检查是否导入了多余的包 -->
        <module name="RedundantImport"/>
        <!-- 没用的import检查,比如:1.没有被用到2.重复的3.import java.lang的4.import 与该类在同一个package的 -->
        <module name="UnusedImports" />

        <!-- 注释检查 -->
        <!-- 检查构造函数的javadoc -->
        <module name="JavadocType">
            <property name="allowUnknownTags" value="true"/>
            <message key="javadoc.missing" value="类注释:缺少Javadoc注释。"/>
        </module>

        <!-- 命名检查 -->
        <!-- 包名的检查(只允许小写字母),默认^[a-z]+(\.[a-zA-Z_][a-zA-Z_0-9_]*)*$ -->
        <module name="PackageName">
            <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
            <message key="name.invalidPattern" value="Package name ''{0}'' must match pattern ''{1}''."/>
        </module>
        <!-- 仅仅是static型的变量(不包括static final型)的检查 -->
        <module name="StaticVariableName" />
        <!-- Class或Interface名检查,默认^[A-Z][a-zA-Z0-9]*$-->
        <module name="TypeName">
            <message key="name.invalidPattern" value="Type name ''{0}'' must match pattern ''{1}''."/>
        </module>
        <!-- 检查接口类型参数名是否符合指定的模式,默认"^[A-Z]$" -->
        <module name="InterfaceTypeParameterName">
            <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
            <message key="name.invalidPattern" value="Interface type name ''{0}'' must match pattern ''{1}''."/>
        </module>
        <!-- 检查类类型参数名是否符合指定的模式,默认"^[A-Z]$" -->
        <module name="ClassTypeParameterName">
            <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
            <message key="name.invalidPattern" value="Class type name ''{0}'' must match pattern ''{1}''."/>
        </module>
        <!-- 检查方法类型参数名称是否符合指定的模式,默认"^[A-Z]$"-->
        <module name="MethodTypeParameterName">
            <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
            <message key="name.invalidPattern" value="Method type name ''{0}'' must match pattern ''{1}''."/>
        </module>
        <!-- 非static型变量的检查 -->
        <module name="MemberName">
            <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
            <message key="name.invalidPattern" value="Member name ''{0}'' must match pattern ''{1}''."/>
        </module>
        <!-- 方法名的检查 -->
        <module name="MethodName">
            <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/>
            <message key="name.invalidPattern" value="Method name ''{0}'' must match pattern ''{1}''."/>
        </module>
        <!-- 方法的参数名 -->
        <module name="ParameterName">
            <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
            <message key="name.invalidPattern" value="Parameter name ''{0}'' must match pattern ''{1}''."/>
        </module>
        <!-- 常量名的检查(只允许大写),默认^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$ -->
        <module name="ConstantName" />
        <!-- 局部的final变量,包括catch中的参数的检查 -->
        <module name="LocalFinalVariableName" />
        <!-- 局部的非final型的变量,包括catch中的参数的检查 -->
        <module name="LocalVariableName" />
        <!-- 检查catch参数名是否符合指定的模式,默认"^(e|t|ex|[a-z][a-z][a-zA-Z]+)$" -->
        <module name="CatchParameterName"/>
        <!-- 验证标识符名称中的缩写(连续大写字母)长度。-->
        <module name="AbbreviationAsWordInName">
            <!-- 指出目标标识符(类、接口、变量和方法名称中的缩写,等等)中允许连续大写字母的数量。 -->
            <property name="allowedAbbreviationLength" value="6"/>
        </module>

        <!-- 定义检查 -->
        <!-- 检查数组类型定义的样式 -->
        <module name="ArrayTypeStyle"/>
        <!-- 检查long型定义是否有大写的“L” -->
        <module name="UpperEll"/>

        <!-- 长度检查 -->
        <!-- 检查长方法和构造函数,默认最大150 -->
        <module name="MethodLength">
            <property name="tokens" value="METHOD_DEF"/>
            <property name="max" value="150"/>
            <property name="countEmpty" value="false"/>
        </module>

        <!-- 方法的参数个数。 并且不对构造方法进行检查-->
        <module name="ParameterNumber">
            <property name="max" value="8" />
            <property name="ignoreOverriddenMethods" value="true"/>
            <property name="tokens" value="METHOD_DEF" />
        </module>

        <!-- 空格检查-->
        <!-- 检查初始化式的空白填充。默认非空 -->
        <module name="EmptyForInitializerPad"/>
        <!-- 检查迭代器的空填充,默认非空 -->
        <module name="EmptyForIteratorPad"/>
        <!-- 方法名后跟左圆括号"(" -->
        <module name="MethodParamPad" />
        <!-- 在类型转换时,不允许左圆括号右边有空格,也不允许与右圆括号左边有空格 -->
        <module name="TypecastParenPad" />
        <!-- 检查通用标记周围的空格(尖括号)"<"和">"是正确的典型约定。该约定是不可配置的。 -->
        <module name="GenericWhitespace"/>
        <!-- 检查在某个特定关键字之后应保留空格 -->
        <module name="NoWhitespaceAfter"/>
        <!-- 检查在某个特定关键字之前应保留空格 -->
        <module name="NoWhitespaceBefore"/>
        <!-- 操作符换行策略检查 -->
        <module name="OperatorWrap"/>
        <!-- 圆括号空白 -->
        <module name="ParenPad"/>
        <!-- 检查分隔符是否在空白之后 -->
        <module name="WhitespaceAfter"/>
        <!-- 检查分隔符周围是否有空白 -->
        <module name="WhitespaceAround"/>
        <!-- 检查非空白字符之间的空格不能超过一个。 -->
        <module name="SingleSpaceSeparator"/>
        <!-- 检查头、包、所有导入声明、字段、构造函数、方法、嵌套类、静态初始化器和实例初始化器之后的空行分隔符。 -->
        <module name="EmptyLineSeparator">
            <property name="tokens" value="VARIABLE_DEF, METHOD_DEF"/>
        </module>

        <!-- 修饰符检查 -->
        <!-- 检查修饰符的顺序是否遵照java语言规范,默认public、protected、private、abstract、static、final、transient、volatile、synchronized、native、strictfp -->
        <module name="ModifierOrder"/>
        <!-- 检查接口和annotation中是否有多余修饰符,如接口方法不必使用public -->
        <module name="RedundantModifier"/>

        <!-- 代码块检查 -->
        <!-- 检查是否有嵌套代码块 -->
        <module name="AvoidNestedBlocks"/>
        <!-- 检查是否有空代码块 -->
        <module name="EmptyBlock"/>
        <!-- 检查空的catch块。默认情况下,check允许包含任何注释的空catch块。 -->
        <module name="EmptyCatchBlock">
            <!-- 如果需要异常的变量名,或者忽略,或者有任何注释,则配置检查来抑制空catch块-->
            <property name="exceptionVariableName" value="expected|ignore"/>
        </module>
        <!-- 检查左大括号位置 -->
        <module name="LeftCurly"/>
        <!-- 检查代码块是否缺失{} -->
        <module name="NeedBraces"/>
        <!-- 检查右大括号位置 -->
        <module name="RightCurly"/>

        <!-- 代码检查 -->
        <!-- 检查default是否在switch语句中的所有case之后。 -->
        <module name="DefaultComesLast"/>
        <!-- 检查空的代码段 -->
        <module name="EmptyStatement"/>
        <!-- 检查字符串字面值的任何组合是否位于equals()比较的左侧。还检查分配给某些字段的字符串字面量(例如someString。= (anotherString =“文本”))。 -->
        <module name="EqualsAvoidNull"/>
        <!-- 检查在重写了equals方法后是否重写了hashCode方法 -->
        <module name="EqualsHashCode"/>
        <!-- 检查switch代码的case中是否缺少break,return,throw和continue。 -->
        <module name="FallThrough"/>
        <!-- 检查局部变量或参数是否隐藏了类中的变量 -->
        <module name="HiddenField">
            <property name="tokens" value="VARIABLE_DEF"/>
            <property name="ignoreSetter" value="true" />
            <property name="ignoreConstructorParameter" value="true" />
        </module>
        <!-- 检查某些异常类型不会出现在catch语句中。 -->
        <module name="IllegalCatch">
            <!-- 指定要拒绝的异常类名。 -->
            <property name="illegalClassNames" value="Error,java.lang.Error"/>
        </module>
        <!-- 检查指定的类型是否声明为要抛出。声明一个方法会引发java.lang.Error或java.lang.RuntimeException几乎是不可接受的。 -->
        <!--<module name="IllegalThrows"/>-->
        <!-- 检查子表达式中是否有赋值操作 -->
        <module name="InnerAssignment"/>
        <!-- 检查switch语句是否有default -->
        <module name="MissingSwitchDefault"/>
        <!-- 检查for循环控制变量是否在for块中被修改。-->
        <module name="ModifiedControlVariable"/>
        <!-- 检查是否有过度复杂的布尔表达式 -->
        <module name="SimplifyBooleanExpression"/>
        <!-- 检查是否有过于复杂的布尔返回代码段 -->
        <module name="SimplifyBooleanReturn"/>

        <!-- 类设计检查 -->
        <!-- 检查类是否为扩展设计l -->
        <!-- 检查只有private构造函数的类是否声明为final -->
        <module name="FinalClass"/>
        <!-- 检查每个顶级类、接口、枚举或注释是否驻留在自己的源文件中。-->
        <module name="OneTopLevelClass"/>
        <!-- 检查接口是否仅定义类型 -->
        <module name="InterfaceIsType"/>
        <!-- 检查类成员的可见度 检查类成员的可见性。只有static final 成员是public的
        除非在本检查的protectedAllowed和packagedAllowed属性中进行了设置-->
        <module name="VisibilityModifier">
            <property name="packageAllowed" value="true"/>
            <property name="protectedAllowed" value="true"/>
        </module>

        <!-- 语法 -->
        <!-- String的比较不能用!= 和 == -->
        <module name="StringLiteralEquality"/>
        <!-- 限制for循环最多嵌套3层 -->
        <module name="NestedForDepth">
            <property name="max" value="3"/>
        </module>
        <!-- if最多嵌套4层 -->
        <module name="NestedIfDepth">
            <property name="max" value="4"/>
        </module>
        <!-- 检查未被注释的main方法,排除以Appllication结尾命名的类 -->
        <!--<module name="UncommentedMain">
            <property name="excludedClasses" value=".*[Application,Test,Server]$"/>
        </module>-->
        <!-- 禁止使用System.out.println -->
        <module name="Regexp">
            <property name="format" value="System\.out\.println"/>
            <property name="illegalPattern" value="true"/>
        </module>

        <!--try catch 异常处理数量 3-->
        <module name="NestedTryDepth ">
            <property name="max" value="3"/>
        </module>
        <!-- 检查没有带零个参数的方法finalize。 -->
        <module name="NoFinalizer"/>
        <!-- clone方法必须调用了super.clone() -->
        <module name="SuperClone" />
        <!-- finalize 必须调用了super.finalize() -->
        <module name="SuperFinalize" />
        <!-- 检查每行是否只有一条语句。-->
        <module name="OneStatementPerLine"/>
        <!-- 检查是否将重载方法分组在一起。重载的方法具有相同的名称但不同的签名,其中签名可以因输入参数的数量或输入参数的类型或两者的数量而不同。-->
        <module name="OverloadMethodsDeclarationOrder"/>
        <!-- 确保类有包声明,以及(可选的)包名是否与源文件的目录名匹配。-->
        <module name="PackageDeclaration"/>
        <!-- 禁止给参数赋值。-->
        <module name="ParameterAssignment"/>
        <!-- 检查语句或表达式中是否使用了不必要的括号。-->
        <!--<module name="UnnecessaryParentheses"/>-->

        <!--1.Annotation检查:AnnotationLocation:注解规范, AnnotationOnSameLine:注解同行规范-->
        <module name="AnnotationLocation">
            <!--注解应该独占一行-->
            <property name="allowSamelineMultipleAnnotations" value="false"/>
            <property name="allowSamelineSingleParameterlessAnnotation" value="false"/>
            <property name="allowSamelineParameterizedAnnotation" value="false"/>
            <!--检查对象:类、接口、枚举、方法、构造器、变量-->
            <property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
        </module>
        <module name="AnnotationOnSameLine">
            <!--检查对象:参数-->
            <property name="tokens" value="PARAMETER_DEF" />
        </module>

    </module>
</module>

suppressions.xml 可以配置忽略检查的文件,比如忽略未使用 jar 包导入的校验规则,具体配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.1//EN"
        "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions>
    <!-- Suppresses the "Unused import" warning for all files in the project -->
    <suppress files=".*" checks="UnusedImport" />

</suppressions>

除此之外,还需要在 build.gradle 中引入checkstyle 的插件,因为我们在使用 Gradle 通常都是多模块构建,所以统一放在 allprojects 配置当中,作为子项目的通用配置,该插件默认就会找 config/checkstyle(目录可修改) 下面的配置文件。

具体代码如下:

allprojects {
    apply plugin: 'java-library'
    apply plugin: 'idea'
    apply plugin: 'io.spring.dependency-management'
    apply plugin: 'maven-publish'
    apply plugin: 'checkstyle'

    // JVM 版本号要求
    sourceCompatibility = 1.8
    targetCompatibility = 1.8

    // java编译的时候缺省状态下会因为中文字符而失败
    [compileJava, compileTestJava]*.options*.encoding = 'UTF-8'

    // 代码规范检查
    checkstyle {
        // The version of the code quality tool to be used.
        toolVersion = "8.8"

        // Whether or not to allow the build to continue if there are warnings.
        ignoreFailures = false

        // Whether or not rule violations are to be displayed on the console.
        showViolations = true
    }

}

其中定义了 checkstyle 的 task,声明了对应插件的版本,以及异常情况下是否继续构建和是否在构建控制台显示违反的规则。

四、测试

至此,Gradle 项目就已经集成好了 checkstyle 插件,接下来是测试。简单编写了一个测试代码,其中包含了几点不规范的地方。

在这里插入图片描述

执行 gradle build 时候,可以看到控制台生成构建任务 checkstyleMain 代码风格检查时候执行异常,阻止了 Gradle 构建的执行,同时会将检查结果生成一个 HTML 文件。

在这里插入图片描述

打开 HTML 文件,可以看到对应那个类存在的问题和触发的规则,以方便对代码修改,符合规范的代码才能通过构建流程。

在这里插入图片描述

另外,也可以配置在 git 本地提交的时候自动触发构建,符合代码规范才允许提交。

五、总结

checkstyle 能一定程度上约束和统一代码的风格,对于新项目强烈推荐使用,但是对于老的项目,有一定的历史包袱在里面,想要集成适配的话会有一定的开发成本,要看具体项目的投入来评估。但俗话也说得好,规范只是用来约束君子,而防不了盗贼,所以除了工具的协助外,更多其实在日常写代码中需要我们不断去思考和沉淀,怎样能将代码写得更加优雅、易读、可维护和可扩展,而不只是业务代码上的堆砌,在一些关键代码善于运用一些设计模式来简化业务流程,从而提高项目代码可读性和可维护性,但也要避免过度设计。

以上整体就是 Gradle 集成 checkstyle 的流程和个人的一些思考,如有问题,还请指出,也欢迎大家与我一起交流学习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/543436.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二分查找的总结

一、二分查找 1.思路分析 这道题目的前提是数组为有序数组&#xff0c;同时题目还强调数组中无重复元素&#xff0c;因为一旦有重复元素&#xff0c;使用二分查找法返回的元素下标可能不是唯一的&#xff0c;这些都是使用二分法的前提条件&#xff0c;当大家看到题目描述满足如…

Ampere Computing 发布全新 AmpereOne 系列处理器,192 个自研核

2023 年 5 月 19 日&#xff0c;中国北京——Ampere Computing 宣布推出全新 AmpereOne™ 系列处理器&#xff0c;该处理器拥有多达 192 个单线程 Ampere 核&#xff0c;内核数量为业界最高。这是第一款基于 Ampere 新自研核的产品&#xff0c;由 Ampere 自有 IP 全新打造。 致…

chatgpt赋能Python-python3_6怎么打开

Python 3.6&#xff1a;新时代的编程语言 Python 3.6是一种全新的编程语言版本&#xff0c;它提供了全新的功能和改进&#xff0c;使得编程过程更加简便且实用。无论你是编程新手还是老手&#xff0c;本文将教你如何打开Python 3.6&#xff0c;并带你了解Python 3.6的优点。 …

详解c++---多态

目录标题 为什么会有多态什么是虚函数的重写多态的定义特殊的重写重载&#xff0c;覆盖&#xff08;重写&#xff09;&#xff0c;隐藏&#xff08;重定义&#xff09;的对比final和override抽象类多态的原理验证虚表所在额度位置多继承的多态原理菱形虚拟继承多态的一些小点 为…

登录ChatGPT时提示Sorry, you have been blocked(对不起,您已被阻止)

问题描述 今天想使用ChatGPT&#xff0c;结果突然来了这么个问题&#xff0c;就问你吓不吓人&#xff1f;&#xff1f;&#xff1f;我以为我的账号被封了&#xff01; 原因分析 内容过滤&#xff1a;某些平台或网站可能使用内容过滤系统&#xff0c;该系统可能将AI语言模型视…

全文索引搜索引擎Zinc

什么是 Zinc &#xff1f; ZincSearch 是一个搜索引擎&#xff0c;可用于文本数据、日志、指标、事件等。它允许您进行全文搜索&#xff0c;包括将服务器日志发送到 ZincSearch、推送您的应用程序数据、提供全文搜索或在您的应用程序中构建搜索栏。具备与 Elasticsearch API 的…

Android WebView加载网页html文件显示加载进度

效果图如下&#xff1a; 一、视图绑定 通过视图绑定功能&#xff0c;您可以更轻松地编写可与视图交互的代码。在模块中启用视图绑定之后&#xff0c;系统会为该模块中的每个 XML 布局文件生成一个绑定类。绑定类的实例包含对在相应布局中具有 ID 的所有视图的直接引用。 在大…

Navicat 15中文安装教程

Navicat 15中文安装教程 附上百度网盘链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1OZNjcuEHnsZqBa9A-e_twQ 提取码&#xff1a;2phg 里面有两个版本&#xff0c;分别是64位和32位&#xff0c;大家可以根据自己的情况进行安装 下面是详细安装教程 1、选择安装包…

Sonar加入jenkins流水线

前提&#xff1a;已搭建sonarqube 1、配置sonarqube server jenkins 中manage jenkins-configure System配置sonarqube server 2、准备sonar环境 在jenkins项目的构建环境步骤中&#xff0c;勾选prepare SonarQube environment token需要提前在凭据里添加一个token 3、执行s…

ES6中flat与flatMap使用

1、方法介绍 数组的成员有时还是数组&#xff0c;Array.prototype.flat()用于将嵌套的数组“拉平”&#xff0c;变成一维的数组。该方法返回一个新数组&#xff0c;对原数据没有影响。 [1, 2, [3, 4]].flat() // [1, 2, 3, 4]上面代码中&#xff0c;原数组的成员里面有一个数…

InnoDB数据页结构

什么是页&#xff1f;什么是数据页&#xff1f; 页是InnoDB管理存储空间的基本单元&#xff0c;一个页的大小一般是16k。 InnoDB有许多不同的页&#xff0c;有存放表空间头部信息的页&#xff0c;INODE信息的页&#xff0c;当然还有存放我们记录信息的页&#xff0c;这个页叫…

【苹果】Apple Store 更换ID教程

在此之前需要准备的项目&#xff1a; 一台苹果手机【教程环境&#xff1a;ios15 in iPhone11】一个新的苹果ID账号一个具备完整阅读能力愿意看完教程的人 教程开始 第一步&#xff1a;解锁您的 iPhone 第二步&#xff1a;打开你的应用商店 第三步&#xff1a;点击右上角头像…

Linux驱动快速入门(vscode的使用)

vscode精确跳转前提&#xff1a; 1、安装了clangd插件 2、禁止了c/c intellisense&#xff1a; 3、在Linux内核源码首目录下有compile_commands.json文件&#xff0c;且这个文件内容“cc”改为了“xxxx-gcc”&#xff0c;后先清理之前编译的&#xff0c;后用bear make编译。…

ChatGPT官方APP上线:速度极快且免费、增加语音识别,网友:真香

安卓版也马上要来。 很强大&#xff0c;很简洁&#xff0c;而且它太快了。 这就是人们对几小时前 OpenAI 发布的 ChatGPT 官方版 App 的评价&#xff1a; ChatGPT 推出近半年以来&#xff0c;已经从新鲜的事物成为改变整个科技领域的推手。有机构统计认为&#xff0c;早在今年…

【手撕代码系列】JS手写实现深拷贝

公众号&#xff1a;Code程序人生&#xff0c;分享前端所见所闻 深拷贝是在计算机科学中非常重要的概念&#xff0c;尤其是在处理数据结构和对象的时候。深拷贝的目的是创建一个新的对象&#xff0c;它有自己的内存空间&#xff0c;并且其中的所有值都是原始对象的副本。这样做的…

某大型啤酒企业:CACTER邮件网关成功替换IronPort!安全防护升级

客户案例 某大型啤酒厂商的公司规模和市场份额多年来始终都处于行业领先地位&#xff0c;积极赞助多项体育赛事&#xff0c;持续丰富和提升品牌形象。 作为一家具有全球影响力的企业&#xff0c;自然也成为了全球黑客等攻击团伙的重点目标&#xff0c;而系统攻击的开端便是钓…

互联网医院牌照的申请流程|互联网医院资质申请难吗

互联网医院系统现在已经发展的很成熟了&#xff0c;国家也出台了很多鼓励的相关政策&#xff0c;所以很多的医疗机构也纷纷的开始开发互联网医院系统&#xff0c;当然要想互联网医院系统能够正常的运行看诊&#xff0c;还需要申办互联网医院牌照&#xff0c;接下来给大家介绍一…

GE Hydran M2 监测各种故障气体的综合值

Hydran M2 是一种紧凑型永久安装在线变压器监测设备&#xff0c;可在出现故障情况时向人员发出警报。它持续监测各种故障气体的综合值&#xff08;以 ppm 为单位&#xff09;或仅监测氢气值&#xff08;取决于购买的传感器&#xff09;。此外&#xff0c;它还跟踪油中的水分&am…

Redis自学之路—基础数据结构(二)

目录 简介 Redis应用场景 Redis基础数据结构 一、string&#xff08;字符串&#xff09; string类型相关指令 二、list&#xff08;列表&#xff09; list类型相关指令 三、hash&#xff08;字典&#xff09; hash类型相关指令 四、set&#xff08;集合&#xff09; se…

Mysql多表和窗口函数

1.多表查询--自关联查询 # 格式: select * from A join A on 条件; 或者 select * from A left join A on 条件; # 自关联查询的用法和 内连接, 外连接等操作一模一样, 只不过是: 表自己关联自己. # 应用场景: 分类表(多级), 行政区域表(3级, 省市区). # 查询结果: 跟上述多…