功能Java示例 第8部分–更多纯函数

这是第8部分,该系列的最后一部分称为“ Functional Java by Example”。

我在本系列的每个部分中发展的示例是某种“提要处理程序”,用于处理文档。 在上一期文章中,我们已经使用Vavr库看到了一些模式匹配,并且还将故障也视为数据 ,例如,采用替代路径并返回到功能流程。

在本系列的最后一篇文章中,我将功能发挥到了极致 :一切都变成了功能。

如果您是第一次来,最好是从头开始阅读。 它有助于了解我们从何处开始以及如何在整个系列中继续前进。

这些都是这些部分:

  • 第1部分–从命令式到声明式
  • 第2部分–讲故事
  • 第3部分–不要使用异常来控制流程
  • 第4部分–首选不变性
  • 第5部分–将I / O移到外部
  • 第6部分–用作参数
  • 第7部分–将失败也视为数据
  • 第8部分–更多纯函数

我将在每篇文章发表时更新链接。 如果您通过内容联合组织来阅读本文,请查看我博客上的原始文章。

每次代码也被推送到这个GitHub项目 。

最大化运动部件

您可能已经听过Micheal Feathers的以下短语:

OO通过封装运动部件使代码易于理解。 FP通过最大程度地减少运动部件来使代码易于理解。

好的,让我们稍稍忘记上一期中的故障恢复,然后继续下面的版本:

 FeedHandler { class FeedHandler { List<Doc> handle(List<Doc> changes, Function<Doc, Try<Resource>> creator) { changes .findAll { doc -> isImportant(doc) } .collect { doc -> creator.apply(doc) }.map { resource -> setToProcessed(doc, resource) }.getOrElseGet { e -> setToFailed(doc, e) } } } private static boolean isImportant(doc) { doc.type == 'important' } private static Doc setToProcessed(doc, resource) { doc.copyWith( status: 'processed' , apiId: resource.id ) } private static Doc setToFailed(doc, e) { doc.copyWith( status: 'failed' , error: e.message ) }  } 

替换为功能类型

我们可以使用对函数接口类型的变量(例如PredicateBiFunction的引用来替换每种方法。

A)我们可以替换一个接受1个参数并返回boolean的方法

 private static boolean isImportant(doc) { doc.type == 'important'  } 

谓词

 private static Predicate<Doc> isImportant = { doc -> doc.type == 'important'  } 

B),我们可以替换一个接受2个参数并返回结果的方法

 private static Doc setToProcessed(doc, resource) { ...  }  private static Doc setToFailed(doc, e) { ...  } 

具有双功能

 private static BiFunction<Doc, Resource, Doc> setToProcessed = { doc, resource -> ...  }  private static BiFunction<Doc, Throwable, Doc> setToFailed = { doc, e -> ...  } 

为了实际调用封装在(Bi)Function中的逻辑,我们必须对其调用apply 。 结果如下:

 FeedHandler { class FeedHandler { List<Doc> handle(List<Doc> changes, Function<Doc, Try<Resource>> creator) { changes .findAll { isImportant } .collect { doc -> creator.apply(doc) .map { resource -> setToProcessed.apply(doc, resource) }.getOrElseGet { e -> setToFailed.apply(doc, e) } } } private static Predicate<Doc> isImportant = { doc -> doc.type == 'important' } private static BiFunction<Doc, Resource, Doc> setToProcessed = { doc, resource -> doc.copyWith( status: 'processed' , apiId: resource.id ) } private static BiFunction<Doc, Throwable, Doc> setToFailed = { doc, e -> doc.copyWith( status: 'failed' , error: e.message ) }  } 

将所有输入移至功能本身

我们将所有内容移至方法签名,以便FeedHandler的handle方法的调用者可以提供自己的那些功能的实现。

方法签名将更改为:

 List<Doc> handle(List<Doc> changes, Function<Doc, Try<Resource>> creator) 

 List<Doc> handle(List<Doc> changes, Function<Doc, Try<Resource>> creator, Predicate<Doc> filter, BiFunction<Doc, Resource, Doc> successMapper, BiFunction<Doc, Throwable, Doc> failureMapper) 

其次,我们将重命名原始(静态) 谓词BiFunction变量

  • isImportant
  • setToProcessed
  • setToFailed

转换为类顶部的新常量 ,反映它们的新作用。

  • DEFAULT_FILTER
  • DEFAULT_SUCCESS_MAPPER
  • DEFAULT_FAILURE_MAPPER

客户端可以完全控制是否将默认实现用于某些功能,或者何时需要接管自定义逻辑。

例如,当仅需要定制故障处理时,可以这样调用handle方法:

 BiFunction<Doc, Throwable, Doc> customFailureMapper = { doc, e -> doc.copyWith( status: 'my-custom-fail-status' , error: e.message )  }  new FeedHandler().handle(..., FeedHandler.DEFAULT_FILTER, FeedHandler.DEFAULT_SUCCESS_MAPPER, customFailureMapper ) 

如果您的语言支持,则可以通过分配默认值来确保客户端实际上不必提供每个参数。 我正在使用支持将默认值分配给方法中的参数的Apache Groovy :

 List<Doc> handle(List<Doc> changes, Function<Doc, Try<Resource>> creator, Predicate<Doc> filter = DEFAULT_FILTER, BiFunction<Doc, Resource, Doc> successMapper = DEFAULT_SUCCESS_MAPPER, BiFunction<Doc, Throwable, Doc> failureMapper = DEFAULT_FAILURE_MAPPER) 

在我们将应用另一个更改之前,请看一下代码:

 FeedHandler { class FeedHandler { private static final Predicate<Doc> DEFAULT_FILTER = { doc -> doc.type == 'important' } private static final BiFunction<Doc, Resource, Doc> DEFAULT_SUCCESS_MAPPER = { doc, resource -> doc.copyWith( status: 'processed' , apiId: resource.id ) } private static final BiFunction<Doc, Throwable, Doc> DEFAULT_FAILURE_MAPPER = { doc, e -> doc.copyWith( status: 'failed' , error: e.message ) } List<Doc> handle(List<Doc> changes, Function<Doc, Try<Resource>> creator, Predicate<Doc> filter = DEFAULT_FILTER, BiFunction<Doc, Resource, Doc> successMapper = DEFAULT_SUCCESS_MAPPER, BiFunction<Doc, Throwable, Doc> failureMapper = DEFAULT_FAILURE_MAPPER) { changes .findAll { filter } .collect { doc -> creator.apply(doc) .map { resource -> successMapper.apply(doc, resource) }.getOrElseGet { e -> failureMapper.apply(doc, e) } } }  } 

介绍两者

您是否注意到以下部分?

 .collect { doc -> creator.apply(doc) .map { resource -> successMapper.apply(doc, resource) }.getOrElseGet { e -> failureMapper.apply(doc, e) }  } 

请记住, creator的类型是

 Function<Doc, Try<Resource>> 

表示它返回一个Try 。 我们在第7部分中介绍了Try ,它是从Scala等语言中借来的。

幸运的是, collect { doc的“ doc”变量仍在传递给我们需要它的successMapperfailureMapper 范围内 ,但是Try#map的方法签名(接受一个Function )与我们的successMapper之间存在差异一个BiFunctionTry#getOrElseGet也是Try#getOrElseGet ,它也只需要一个Function

从Try Javadocs:

  • map(Function <?super T,?extended U>映射器)
  • getOrElseGet(Function <?super Throwable ,?

简而言之,我们需要从

  1. BiFunction <文档,资源,文档> successMapper
  2. BiFunction <文档,Throwable,文档> failureMapper

  1. 函数<资源,文档> successMapper
  2. 函数<Throwable,Doc> failureMapper

同时仍然可以将原始文档作为输入

让我们介绍两个简单的类型,它们封装了2个BiFunction的2个参数:

 class CreationSuccess { Doc doc Resource resource  }  class CreationFailed { Doc doc Exception e  } 

我们将论点从

  1. BiFunction <文档,资源,文档> successMapper
  2. BiFunction <文档,Throwable,文档> failureMapper

改为功能

  1. 函数<CreationSuccess,Doc> successMapper
  2. 函数<CreationFailed,Doc> failureMapper

现在, handle方法如下所示:

 List<Doc> handle(List<Doc> changes, Function<Doc, Try<Resource>> creator, Predicate<Doc> filter, Function<CreationSuccess, Doc> successMapper, Function<CreationFailed, Doc> failureMapper) { changes .findAll { filter } .collect { doc -> creator.apply(doc) .map(successMapper) .getOrElseGet(failureMapper) }  } 

…… 但是还行不通

Try使mapgetOrElseGet需要分别。 一个

  • 函数<资源,文档> successMapper
  • 函数<Throwable,Doc> failureMapper

这就是为什么我们需要将其更改为另一个著名的FP结构,称为Either

幸运的是Vavr有要么太。 它的Javadoc说:

任一代表两种可能的值。

通常使用这两种类型来区分正确的值(“正确”)或错误的值。

它变得非常抽象:

Either可以是Either.Left或Either.Right。 如果给定的Either是Right并投影到Left,则Left操作对Right值没有影响。 如果给定的Either是Left并投影到Right,则Right操作对Left值没有影响。 如果将“左”投影到“左”或将“右”投影到“右”,则操作会生效。

让我解释以上神秘的文档。 如果我们更换

 Function<Doc, Try<Resource>> creator 

通过

 Function<Doc, Either<CreationFailed, CreationSuccess>> creator 

我们将CreationFailed分配给“ left”参数,该参数通常会保留错误(请参见Either上的Haskell文档 ), CreationSuccess是“ right”(和“正确”)值。

在运行时,该实现曾经返回一个Try ,但是现在可以返回一个Either.Right ,如果成功,例如

 return Either.right( new CreationSuccess( doc: document, resource: [id: '7' ] )  ) 

Either.Left ,但发生故障时除外- 两者都包括原始文档 。 是。

因为现在类型最终匹配,所以我们终于压扁了

 .collect { doc -> creator.apply(doc) .map { resource -> successMapper.apply(doc, resource) }.getOrElseGet { e -> failureMapper.apply(doc, e) }  } 

进入

 .collect { doc -> creator.apply(doc) .map(successMapper) .getOrElseGet(failureMapper)  } 

现在, handle方法如下所示:

 List<Doc> handle(List<Doc> changes, Function<Doc, Either<CreationFailed, CreationSuccess>> creator, Predicate<Doc> filter, Function<CreationSuccess, Doc> successMapper, Function<CreationFailed, Doc> failureMapper) { changes .findAll { filter } .collect { doc -> creator.apply(doc) .map(successMapper) .getOrElseGet(failureMapper) }  } 

结论

我可以说我已经实现了我一开始制定的大多数目标:

  • 是的,我设法避免了重新分配变量
  • 是的,我设法避免了可变数据结构
  • 是的,我设法避免了状态 (至少在FeedHandler中)
  • 是的,我设法支持函数 (使用某些Java内置函数类型和某些第三方库Vavr)

我们已经将所有内容移到了函数签名,以便FeedHandler的handle方法的调用者可以直接传递正确的实现。 如果您从头到尾回顾原始版本,您会注意到在处理更改列表时,我们仍然承担所有责任:

  • 通过某些条件过滤文档列表
  • 为每个文档创建资源
  • 成功创建资源后执行某些操作
  • 无法创建资源时执行其他操作

然而,在第一部分中,这些责任是势在必行写出来,for语句声明,都在一个大聚集在一起handle方法。 现在,最后,每个决定或动作都由具有抽象名称的函数表示,例如“过滤器”,“创建者”,“ successMapper”和“ failureMapper”。 实际上,它以一个或多个函数为参数,成为一个高阶函数。 提供所有参数的责任已经转移到了客户的上层。 如果您查看GitHub项目,您会注意到,对于这些示例,我不得不不断更新单元测试。

有争议的部分

在实践中,如果不需要,我可能不会编写我的(Java)商业代码,例如FeedHandler类在传递通用Java函数类型(即FunctionBiFunctionPredicateConsumerSupplier )方面的使用方式所有这些极端的灵活性。 所有这些都是以可读性为代价的。 是的,Java是一种静态类型的语言,因此,使用泛型时,必须在所有类型参数中都明确使用一种语言,从而导致以下功能的签名困难:

 handle(List<Doc> changes,  Function<Doc, Either<CreationFailed, CreationSuccess>> creator,  Predicate<Doc> filter,  Function<CreationSuccess, Doc> successMapper,  Function<CreationFailed, Doc> failureMapper) 

在普通JavaScript中,您将没有任何类型,并且您必须阅读文档以了解每个参数的期望。

 handle = function (changes, creator, filter, successMapper, failureMapper) 

但是,这是一个折衷方案。 Groovy,也是一种JVM语言, 允许我在本系列的所有示例中省略类型信息,甚至允许我使用Closures(就像Java中的lambda表达式一样)是Groovy中功能编程范例的核心。

更极端的做法是在类级别指定所有类型,以使客户端具有最大的灵活性,以便为不同的FeedHandler实例指定不同的类型。

 handle(List<T> changes,  Function<T, Either<R, S>> creator,  Predicate<T> filter,  Function<S, T> successMapper,  Function<R, T> failureMapper) 

什么时候合适?

  • 如果您完全控制代码,则在特定上下文中使用它来解决特定问题时,这将过于抽象而无法产生任何收益。
  • 但是,如果我将一个库或框架开源(或者在一个组织内向其他团队或部门使用),该库或框架正在各种不同的用例中使用,那么我可能不会事先想到,为灵活性而设计可能值得。 让呼叫者决定如何过滤以及成功或失败的构成是明智之举。

最终,上述内容在API设计 ,是和解耦方面略有涉及,但是在典型的Enterprise Java Java项目中“使一切成为函数”可能需要与您和您的团队成员进行一些讨论。 多年来,一些同事已经习惯了一种更为传统,惯用的代码编写方式。

好的零件

  • 我绝对希望使用不可变的数据结构 (和“参照透明性”)来帮助推断我的数据所处的状态。想想Collections.unmodifiableCollection的集合。 在我的示例中,我将Groovy的@Immutable用于POJO,但在普通的Java库(例如Immutables , AutoValue或Project Lombok)中也可以使用。
  • 最大的改进实际上是导致了一种更具功能性的样式:使代码讲故事 ,这主要是关于分离关注点并适当地命名事物。 在任何编程风格(即使是OO:D)中,这都是一个好习惯,但这确实消除了混乱,并允许引入(纯)函数。
  • 在Java中,我们习惯于以特定方式进行异常处理,以至于像我这样的开发人员很难提出其他解决方案。 像Haskell这样的功能语言仅返回错误代码,因为“ Niklaus Wirth认为异常是GOTO的转世,因此省略了它们” 。 在Java中,可以使用CompletableFuture或…
  • 通过引入第3方库(例如Vavr)可在您自己的代码库中使用的特定类型(例如TryEither )可以极大地帮助您启用更多以FP样式编写的选项 ! 我以流畅的方式编写“成功”或“失败”路径并且可读性很强,这让我非常着迷。

Java不是F#的Scala或Haskell或Clojure,它最初遵循的是面向对象编程(OOP)范例,就像C ++,C#,Ruby等一样,但是在Java 8中引入了lambda表达式并结合了一些很棒的功能之后如今,开放源代码库如今,开发人员绝对可以选择OOP和FP必须提供的最佳元素

做系列的经验教训

我在很早以前就开始了这个系列的讨论 。 早在2017年,我发现自己在一段代码上进行了一些FP风格的重构,这启发了我去寻找一系列名为“ Functional Java by Example”的文章的示例 。 这成为我在每个批次中一直使用的FeedHandler代码。

那时我已经对所有的代码进行了更改,但是当我计划编写实际的博客文章时,我常常想到:“我只是不能展示重构,我必须进行实际解释!” 那就是我为自己埋下陷阱的地方,因为在整个过程中,我坐下来写作的时间越来越少。 (曾经写过博客的任何人都知道,简单地分享要点和撰写可理解的英语co的连贯段落在时间上的区别)

下次当我想到进行一系列学习时,我将向Google返回一些经验教训:

  1. 如果您不准备在发布新文章时每次准备发布的每期文章中都没有更新所有链接,则不要在每篇文章的顶部都包含目录(TOC)。 如果将这些交叉发布到公司的公司博客中,那么工作量是原来的2倍🙂
  2. 随着时间的流逝,您可能会得出自己宁愿偏离主要用例的结论,也就是刚开始使用的Big Coding Example。 我宁愿展示更多的FP概念(例如, 使用FP技术时的生硬,记忆,懒惰以及不同的心态),但我不能很好地适应以前做过的重构和我在一开始建立的TOC 。 如果您正在撰写有关特定概念的文章,通常会找到一个合适的示例来帮助说明手头的特定概念,并且仍然与读者相关。 随着时间的流逝,我将获得更好的洞察力,从而可以确定接下来要写的更好的东西以及要使用的更合适的示例。 下次,我将不得不寻找一种方法来给(更好:允许)我自己一些创作上的自由😉

  • 《功能性思维:语法惊人的范式 》,尼尔·福特(Neil Ford)着,它展示了FP思维的新方法,也以不同的方式处理问题。
  • 40分钟内的函数式编程 Russ Olsen的Youtube视频解释说:“这些数学家证明1 + 1 = 2需要379页。 让我们看看我们可以从中窃取什么好主意。”
  • 为什么不对函数进行规范编程? 理查德·费尔德曼(Richard Feldman)的Youtube视频,他解释了为什么OOP变得非常流行,以及FP为何不是常态。 正如您所知,他是Elm核心团队的成员,与FP有一定的联系。
  • (耦合)控制的倒置有关“托管功能”的深思熟虑的文章。 您想要抽象吗?

如果您有任何意见或建议,我很想听听他们的意见!

编程愉快! 🙂


翻译自: https://www.javacodegeeks.com/2019/12/functional-java-by-example-part-8-more-pure-functions.html

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

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

相关文章

tensorflow 小于_坐姿不对,屏幕就变模糊!教你用TensorFlow做一款“隐形背背佳”...

大数据文摘出品作为一个上班族&#xff0c;每天坐在电脑前那么久&#xff0c;难免出现腰酸背痛的情况&#xff0c;时间长了甚至脊柱都歪曲变形了&#xff0c;这可不行&#xff01;一定要克制住自己的坐姿。这里有款“隐形背背佳”&#xff0c;要不要了解一下&#xff1f;一位名…

python里随机抽取样本_概率分布和抽样分布基础知识及Python实现

本文主要介绍推论统计中的概率分布和抽样分布,本文结构如下: 一、概率分布 随机变量:在一定条件下,某件事情可能发生或者不发生,这个事件就叫随机事件。例如抛硬币哪面朝上。随机变量X就是用来量化随机事件的函数,是将随机事件每一个可能出现的结果映射到数值的一个函数。…

php 创建目录_使用SMB绕过PHP远程文件包含限制

译文声明本文是翻译文章&#xff0c;文章原作者mannulinux&#xff0c;文章来源&#xff1a;mannulinux.org 原文地址&#xff1a;http://www.mannulinux.org/2019/05/exploiting-rfi-in-php-bypass-remote-url-inclusion-restriction.html译文仅供参考&#xff0c;具体内容表达…

eas系统服务器地址,EAS7.0EAS7.5服务端及其客户端标准配置介绍

金蝶EAS是基于JavaEE的大型企业应用。目前服务端支持以下主流软硬件环境。适用版本&#xff1a;EAS7.0 EAS703 EAS7.51.金蝶EAS服务端支持的软硬件环境注&#xff1a;标志为部署支持的环境&#xff0c;可以正常安装配置&#xff0c;但是正式运行前需联系金蝶技术支持。2.客户端…

Java的Kafka:构建安全,可扩展的消息传递应用程序

使用Okta的身份管理平台轻松部署您的应用程序 使用Okta的API在几分钟之内即可对任何应用程序中的用户进行身份验证&#xff0c;管理和保护。 今天尝试Okta。 当今的用户希望可以通过其计算机&#xff0c;手机&#xff0c;平板电脑或任何其他设备访问您的应用程序&#xff01; …

background复合属性顺序_CSS有哪些好用的字体属性?

本文创建于2020年9月&#xff0c;以下为正文&#xff1a;CSS中有哪些字体属性呢&#xff1f;font&#xff1a;复合属性。设置或检索对象中的文本特征。font-style&#xff1a;设置或检索对象中的字体样式。用于定义字体的风格&#xff0c;如&#xff1a;斜体&#xff08;italic…

转译和编译_10个有趣又能编译为JavaScript的语言,你用过哪些?

点击上方“IT平头哥联盟”&#xff0c;选择“置顶或者星标”你的关注意义重大&#xff01;来源&#xff1a;https://www.sitepoint.com/现代应用相比普通的网页有不同的要求。但是浏览器是一个有着一套(大部分)固定可用的技术的平台&#xff0c;JavaScript依然是web应用的核心语…

OPC服务器如何采集设备的信息,如何将OPC服务器采集的设备数据转为MQTT方式,实现云端发布或订阅...

通过与PLC、智能仪表等硬件设备&#xff0c;以及OPC服务器、数据库等软件建立通讯&#xff0c;进行实时数据采集监控&#xff0c;然后将相关数据转换为数据库、OPC&#xff0c;以及MQTT、HTTP等多种服务接口&#xff0c;实现各类自动化与信息化系统软件灵活对接。MQTT智能网关案…

微信小程序摄像头监控_微信必备黑科技小程序!

↑点击上方蓝字关注极物推荐欢迎分享到朋友圈-不花冤枉钱&#xff0c;历史见真谛对于喜欢购物的朋友们&#xff0c;这绝对是一把利器。只需把商品链接复制粘贴到上面&#xff0c;就可以轻松的查阅到该商品的历史价格&#xff0c;轻松直观的了解商品过去的价格波动&#xff0c;同…

无线打印 airprint 服务器,如何让 Windows 的共享打印机支持 AirPrint

对很多办公室环境来说&#xff0c;局域网共享打印机往往都是刚需&#xff0c;而如果局域网内的设备大多为 Windows 设备&#xff0c;通过 网络共享 的方式就可以轻松将所连接的 USB 打印机共享到局域网。但对同一个局域网内的 Apple 设备而言&#xff0c;因为很多打印机的 Mac …

硒测试中所需的功能和示例

所需功能是用于声明一组基本要求&#xff08;例如浏览器&#xff0c;操作系统&#xff0c;浏览器版本等的组合&#xff09;的类&#xff0c;以对Web应用程序执行自动跨浏览器测试。 当我们尝试通过Selenium自动化测试来自动化测试脚本时&#xff0c;我们需要考虑这些组合&…

边沿触发是什么意思_集基耦合双稳电路,集成化单稳电路,数字逻辑电路,门电路,触发器...

1).箝位器能把脉冲电压维持在某个数值上而使波形保持不变的电路称为箝位器。它也是整形电路的一种。例如电视信号在传输过程中会造成失真&#xff0c;为了使脉冲波形恢复原样&#xff0c;接收机里就要用箝位电路把波形顶部箝制在某个固定电平上。下图中反相器输出端上就有一个箝…

鲸鱼优化算法_盘点 35 个 Java 代码优化细节

代码优化&#xff0c;一个很重要的课题。可能有些人觉得没用&#xff0c;一些细小的地方有什么好修改的&#xff0c;改与不改对于代码的运行效率有什么影响呢&#xff1f;这个问题我是这么考虑的&#xff0c;就像大海里面的鲸鱼一样&#xff0c;它吃一条小虾米有用吗&#xff1…

powerbi导入地图_Power BI系列教程之powerBI功能介绍及使用导引(一)

作为从事数据分析相关工作的小伙伴&#xff0c;我们总会遇到一些工作是每周、每月甚至每天都是重复做的工作&#xff0c;这个时候我们有没有一种结构化的方法来处理这一些数据呢&#xff1f;答案是肯定的&#xff0c;微软为了满足广大职场数据分析人员的需求&#xff0c;开发了…

模糊搜索怎么实现_干货 | 你真的了解自己是怎么搜索的吗_01

「干货」栏目的开启是为了帮大家科普学习关于品牌出海、数字营销与跨境电商行业相关的知识&#xff0c;以及我们在业内会遇到的情况和一些规避的方法。第一讲搜索者我们整个搜索营销活动都是围绕搜索者展开的我们的目的是把搜索者转化为我们的销售机会所以&#xff0c;研究搜索…

linux shc shell脚本_详解shell脚本加密解密软件—gzese和shc

概述以我个人的需求为例&#xff0c;有时写一个脚本需要传密码&#xff0c;如果直接把密码写在脚本里会存在安全问题&#xff0c;一般是把密码写在脚本里&#xff0c;作为参数传给脚本&#xff0c;而保存密码的脚本&#xff0c;使用某种手段加密&#xff0c;令其不可读但是可执…

linux 查看主板sn_如何在 Linux 上查找硬件规格

在 Linux 系统上有许多工具可用于查找硬件规格。-- Sk(作者)在 Linux 系统上有许多工具可用于查找硬件规格。在这里&#xff0c;我列出了四种最常用的工具&#xff0c;可以获取 Linux 系统的几乎所有硬件(和软件)细节。好在是这些工具在某些 Linux 发行版上默认预装。我在 Ubun…

laravel 分词搜索匹配度_【地名地址】面向智慧城市的高精度地名地址匹配方法...

点击上方蓝字关注我们↑↑↑↑原 文 摘 要针对智慧城市建设中各种业务数据对地名地址匹配准确度和效率不高的问题&#xff0c;本文提出一种面向智慧城市的高精度地名地址匹配方法。该方法在基于中文分词的地名地址匹配技术框架下&#xff0c;综合利用精细化地名地址库构建、地名…

使用通用mapper实现条件查询_使用dsum轻松搞定多条件查询,学会它,再也想用sumifs了...

在excel中条件求和想必大家都不陌生&#xff0c;这个可以说是我们工作中经常遇到的问题&#xff0c;常见的条件求和函数有sumif以及sumifs&#xff0c;但是还有一个更加强但知道的人却非常少的函数&#xff0c;他就是dsum函数&#xff0c;dsum相交于sumif以及sumifs函数理解起来…

输入文字自动生成图片_批量生成变化的图片文字海报

最近“双十一”活动大家已经进入了鸡血状态&#xff0c;运营的小伙伴给设计出了个难题&#xff0c;搞的设计小伙伴们进入了癫狂模式。本着工具提升效率的原则&#xff0c;我又开始去研究如何批量修改图片内容了&#xff0c;小小的成果和大家分享一下。提出问题为每一位支付了定…