提升76%的关键-在ModelMapper中实现性能提升的几种方法

目录

前言

一、ModelMapper基础知识

1、深入ModelMapper

2、深入Configuration配置

3、深入MappingEngineImpl

二、默认加载模式

1、基础测试代码

三、持续优化,慢慢提升

1、增加忽略字段

2、设置忽略空值模式

3、设置命名模式

4、采用精准匹配模式

四、总结


前言

        关于在Java当中把HashMap键值属性转换成JavaBean的关键技术有很多实现方式,在之前的博客中介绍了一种实现方式在Java中使用ModelMapper简化Shapefile属性转JavaBean实战。博客仅介绍了ModelMapper这个框架,它本身是通过对象的反射来进行属性的绑定和赋值的。因此属性的对应寻找上就会耗费一定的时间。后面有朋友联系,说ModelMapper的数据转换性能太差,接口的查询效率大大降低了。原来很快的速度,现在使用了ModelMapper之后,反而不如之前的手动调用SetXXX方法来的快。后来经过交流和现场的复盘,得知在对象转换的过程中,这位朋友一直采用的是ModelMapper的默认转换,设置也是采用默认的配置。因此整个属性的映射过程非常慢。从而导致了整体接口的响应超出了预期。

        那么,如何来优化转换速度,提升转换性能呢?这是本文创作的初衷,很多朋友对ModelMapper对象转换的策略和相关配置不是很熟悉。不会设置转换策略,其实通过一些策略的设置,可以很好的进行转换性能的提升。本文即以解析全球主要城市数据为例,重点介绍如何一步一步的优化转换策略和逻辑,将对象的转换时间性能提升76%的过程。希望通过本文的介绍,让您对掌握和优化ModelMapper有更深的了解。

一、ModelMapper基础知识

        为了更清晰的了解ModelMapper对象,掌握其转换的思想和原理。这里对ModelMapper的核心类、核心类的属性和方法将进行简单的介绍。

1、深入ModelMapper

        为了让大家对ModelMaper有更深入的了解,这里我们对ModelMapper的相关属性和方法进行简单介绍。ModelMapper这个类中有两个最核心的属性,即InheritingConfiguration和MappingEngineImpl,一个是配置器;另外一个是MappingEngineImpl,映射引擎。大家可以在ModelMapper的源码中来查看其实现。

public class ModelMapper {private final InheritingConfiguration config;private final MappingEngineImpl engine;/*** Creates a new ModelMapper.*/public ModelMapper() {config = new InheritingConfiguration();engine = new MappingEngineImpl(config);}xxx
}

        在ModelMapper的构造方法中,可以看到。在每次创建ModelMapper对象的实例时,都会创建配置器实例和映射引擎。可以请大家留意这里的实现方式。除了这两个关键的参数外,还有其它的重要方法,总体来说有以下的一些重要方法(说明,为减少重复,这里将类中重载的部分进行删减):

序号方法名说明
1public <S, D> void addConverter(Converter<S, D> converter)注册一个用于将S类型转换为D类型的转换器。
2public <S, D> TypeMap<S, D> addMappings(PropertyMap<S, D> propertyMap)添加从PropertyMap中定义的显式映射。
3public <S, D> TypeMap<S, D> createTypeMap(Class<S> sourceType, Class<D> destinationType)创建一个新的类型映射,支持通过类类型指定源和目标类型。
4public <S, D> TypeMap<S, D> getTypeMap(Class<S> sourceType, Class<D> destinationType)获取源类型和目标类型之间的类型映射。
5public <S, D> TypeMap<S, D> typeMap(Class<S> sourceType, Class<D> destinationType)获取或创建源类型和目标类型之间的类型映射。
6public Collection<TypeMap<?, ?>> getTypeMaps()获取所有的类型映射
7public <D> D map(Object source, Class<D> destinationType)将源对象映射到目标类型的新实例,支持通过类类型指定目标类型。
8public void map(Object source, Object destination)将源对象的属性映射到目标对象,支持直接操作对象。
9public ModelMapper registerModule(Module module)注册一个模块以扩展ModelMapper的功能。

        在ModelMapper中进行参数转换的重要方法就是map方法,这里只是将方法列出,最终的映射方法在后面进行讲解。接下来看一下,在配置属性对象和映射引擎对象的作用分别是什么?

2、深入Configuration配置

        这里首先来介绍一下配置对象。俗话说,没有规矩不成方圆,因此规矩(即方圆)的设置非常有必要。正确的配置也是参数转换的前提条件。InheritingConfiguration 类中的属性主要负责存储和管理模型映射过程中的各种配置和策略。以下是该类中一些关键属性的介绍:

序号属性说明
1private final Configuration parent;父配置,使得当前配置可以从父配置继承设置
2public final TypeMapStore typeMapStore;TypeMapStore 实例,用于存储和管理类型映射配置。
3public final ConverterStore converterStore;ConverterStore 实例,用于存储和管理转换器,这些转换器用于在不同类型之间转换数据。
4public final ValueAccessStore valueAccessStore;ValueAccessStore 实例,用于存储和管理值读取器,这些读取器用于访问对象的属性值。
5public final ValueMutateStore valueMutateStore; ValueMutateStore 实例,用于存储和管理值写入器,这些写入器用于修改对象的属性值。
6 private NameTokenizer destinationNameTokenizer;定义如何分割目标对象名称的 NameTokenizer
7private NameTransformer destinationNameTransformer;转换目标对象名称的 NameTransformer
8private NamingConvention destinationNamingConvention;定义目标对象命名约定的 NamingConvention
9private MatchingStrategy matchingStrategy;匹配策略的 MatchingStrategy,用于确定如何匹配源和目标属性。
10private Condition<?, ?> propertyCondition;定义属性条件的 Condition
11private NameTokenizer sourceNameTokenizer;定义如何分割源对象名称的 NameTokenizer
12private Boolean fieldMatchingEnabled;

布尔值,用于启用或禁用字段匹配。

13private Boolean ambiguityIgnored;布尔值,用于处理属性匹配中的歧义情况。
14private Boolean fullTypeMatchingRequired;

布尔值,用于确定是否需要完全匹配类型。

15private Boolean implicitMatchingEnabled;布尔值,用于启用或禁用隐式匹配
16private Boolean preferNestedProperties;

布尔值,用于确定是否优先匹配嵌套属性。

17private Boolean skipNullEnabled;布尔值,用于确定是否跳过 null 值
18private Boolean collectionsMergeEnabled;

布尔值,用于启用或禁用集合合并。

19private Boolean useOSGiClassLoaderBridging;

布尔值,用于确定是否使用 OSGi 类加载器桥接。

        上面的这些配置非常重要,默认的配置一定是最宽泛的,为了兼容绝大多数的情况。同时效率应该不是最高的,因为很多没有做优化。因此优化上面的话,就涉及到配置的调优等。在这里面,比较重要的就是分割器,命名分割器对于提高源对象和目标对象的属性匹配度而对其进行分割,求解相似度,经过打分,从而确定一个最优的参数映射关系。这就是NameTokenizer的用法,于此同时,匹配策略也是非常重要,还有一些数据的属性条件等都能提高一定的转换性能。

        来看一下它的默认构造方法,如下代码所示:

/*** Creates an initial InheritingConfiguration.
*/
public InheritingConfiguration() {parent = null;typeMapStore = new TypeMapStore(this);converterStore = new ConverterStore();valueAccessStore = new ValueAccessStore();valueMutateStore = new ValueMutateStore();sourceNameTokenizer = NameTokenizers.CAMEL_CASE;destinationNameTokenizer = NameTokenizers.CAMEL_CASE;sourceNamingConvention = NamingConventions.JAVABEANS_ACCESSOR;destinationNamingConvention = NamingConventions.JAVABEANS_MUTATOR;sourceNameTransformer = NameTransformers.JAVABEANS_ACCESSOR;destinationNameTransformer = NameTransformers.JAVABEANS_MUTATOR;matchingStrategy = MatchingStrategies.STANDARD;fieldAccessLevel = AccessLevel.PUBLIC;methodAccessLevel = AccessLevel.PUBLIC;fieldMatchingEnabled = Boolean.FALSE;ambiguityIgnored = Boolean.FALSE;fullTypeMatchingRequired = Boolean.FALSE;implicitMatchingEnabled = Boolean.TRUE;preferNestedProperties = Boolean.TRUE;skipNullEnabled = Boolean.FALSE;useOSGiClassLoaderBridging = Boolean.FALSE;collectionsMergeEnabled = Boolean.FALSE;}

        从代码中可以看到,默认的配置中,NameTokenizer默认采用的驼峰的命名方法,这也与Java的命名规范息息相关;默认的匹配策略是标准匹配模式;默认的属性访问级别是public,方法的访问级别也是public,忽略空值默认是false等等。感兴趣的朋友可以细细查看。介绍完配置后,下面我们来介绍一下映射引擎。

3、深入MappingEngineImpl

  MappingEngineImpl 的类,它实现了 MappingEngine 接口,提供了模型映射的具体实现。这个类是模型映射框架中的核心实现类,负责具体的映射逻辑和策略应用。通过继承和配置,它提供了强大的自定义能力,以适应不同的映射需求。首先来介绍一下它的属性列表:

序号参数说明
1private final Map<TypePair<?, ?>, Converter<?, ?>> converterCache一个用于存储基于源类型和目标类型对的有条件的转换器缓存。
2private final InheritingConfiguration configuration继承自配置,用于获取模型映射的配
3private final TypeMapStore typeMapStore;存储和管理类型映射的存储。
4private final ConverterStore converterStore;存储和管理转换器的存储。

        在构建ModelMapper的构造方法中,将配置对象传入到映射引擎的对象中,即完成映射引擎与配置的关系,从而可以在进行参数转换进行处理。关于映射引擎如何工作的原理,后面有机会再来进行深入的说明。这里简单先说明一下map方法的调用。调用参数转换时会自动调用map方法,代码如下:

/*** Initial entry point.*/
public <S, D> D map(S source, Class<S> sourceType, D destination,TypeToken<D> destinationTypeToken, String typeMapName) {MappingContextImpl<S, D> context = new MappingContextImpl<S, D>(source, sourceType,destination, destinationTypeToken.getRawType(), destinationTypeToken.getType(),typeMapName, this);D result = null;try {result = map(context);} catch (ConfigurationException e) {throw e;} catch (ErrorsException e) {throw context.errors.toMappingException();} catch (Throwable t) {context.errors.errorMapping(sourceType, destinationTypeToken.getType(), t);}context.errors.throwMappingExceptionIfErrorsExist();return result;}

        最后调用属性的转换方法,即convert方法实现具体的转换逻辑,关键代码如下所示:

        以上就是在ModelMapper的转换过程中比较重要的类的属性和方法的简单介绍。以及具体的应用,当然它后面的各种策略还没有细说。大家可以在官网中进行深度学习。 在了解这些基础的对象之后,我们来进行不同模式下的转换对比。

二、默认加载模式

        首先我们先来看一下在使用默认的配置和策略设置的情况下,对于加载和转换数据的相关耗时情况。在进行默认的信息读取前,对加载的数据属性字段也有一个特定的说明。为了测试转换时数据的属性列的列数对转换的影响,这里我们选取之前的城市信息shapefile文件。这个shapefile文件有7342条数据,属性列个数是137个。

1、基础测试代码

        这里我们采取从7342条数据库中循环读取和转换。最开始在默认的参数配置和映射引擎配置下运行。为了详细记录在读取Shapefile的各个过程中的性能损耗。这里分两个时间点介绍,第一个时间点是解析shp成hashMap集合的耗时,第二是将hashMap集合转换成目标集合的耗时。通过不同的设置模式求解耗时,来得到一个比较好的处理模式。默认情况下,modelMapper没有做任何优化和设置,全部采用默认的配置。数据处理的代码如下所示:

public void convertShp2BeanWithLooseModel() throws Exception {Long startTime = System.currentTimeMillis();File file = new File(SHP_FILE);if (!file.exists()) {System.out.println("文件不存在");}ShapefileDataStore store = new ShapefileDataStore(file.toURI().toURL());store.setCharset(Charset.defaultCharset());// 设置中文字符编码// 获取特征类型SimpleFeatureType featureType = store.getSchema(store.getTypeNames()[0]);CoordinateReferenceSystem crs = featureType.getGeometryDescriptor().getCoordinateReferenceSystem();Integer epsgCode = CRS.lookupEpsgCode(crs, true);List<HashMap<String, Object>> mapList = new ArrayList<HashMap<String,Object>>();ModelMapper modelMapper = new ModelMapper();Long s1 = System.currentTimeMillis();List<Ne10mPopulatedPlaces> dataList = new ArrayList<Ne10mPopulatedPlaces>();SimpleFeatureSource featureSource = store.getFeatureSource();// 执行查询SimpleFeatureCollection simpleFeatureCollection = featureSource.getFeatures();SimpleFeatureIterator itertor = simpleFeatureCollection.features();// 遍历featurecollectionwhile (itertor.hasNext()) {HashMap<String, Object> map = new HashMap<String, Object>();SimpleFeature feature = itertor.next();Collection<Property> p = feature.getProperties();Iterator<Property> it = p.iterator();// 遍历feature的propertieswhile (it.hasNext()) {Property pro = it.next();if (null != pro && null != pro.getValue()) {String field = pro.getName().toString();String value = pro.getValue().toString();map.put(field, value);}}// 获取空间字段org.locationtech.jts.geom.Geometry geometry = (org.locationtech.jts.geom.Geometry) feature.getDefaultGeometry();// 创建WKTWriter对象WKTWriter wktWriter = new WKTWriter();// 将Geometry对象转换为WKT格式的字符串String wkt = wktWriter.write(geometry);String geom = "SRID=" + epsgCode +";" + wkt;//拼接srid,实现动态写入map.put("geom", geom);mapList.add(map);}Long e1 = System.currentTimeMillis();System.out.println("解析shp:"+ (e1 - s1) + "毫秒");Long s2 = System.currentTimeMillis();for(HashMap<String, Object> map : mapList) {Ne10mPopulatedPlaces places = modelMapper.map(map, Ne10mPopulatedPlaces.class);dataList.add(places);}Long e2 = System.currentTimeMillis();System.out.println("转化shp:"+ (e2 - s2) + "毫秒");System.out.println(dataList.size());Long endTime = System.currentTimeMillis();Long time = endTime - startTime;System.out.println("程序运行耗时:"+ time + "毫秒");store.dispose();}

        使用Junit单元测试套件来测试以上代码,运行过后的输出结果如下:

默认模式转换耗时:解析1769毫秒  转换66759毫秒

        可以看到一共7342条数据,解析这些数据的时间很快,1769毫秒,也就是两秒钟不到的时间就解析完成。但是在转换的时候耗时很长,花了将近66秒,将近一分钟了。如果有73420条数据,可能处理的速度会更慢,有没有更好的方式来解决呢?

三、持续优化,慢慢提升

        既然使用默认的配置无法有效提高性能,那么要想提高处理能力呢?本节将结合转换配置器来重点讲解一些优化的步骤。通过使用有效的匹配策略和模式,加速参数转换,提高程序性能。本节将围绕速度和效率,来分享这些方法。所谓优化配置,就是根据配置表类设置不同的策略,因地制宜的进行参数的配置和模式的选择,选择最适合当前对象的转换模式。下面将分别给出设置代码和执行的时间。

1、增加忽略字段

        在之前阐述configuration对象时,我们曾将讲过很多的属性。优化第一步,在实际情况中,比如我们的业务主键pkId或者ID等主键,可能是不需要转换的。在进行映射时,如果要转换的列较多就可以提升一定的处理性能。关键代码如下:

//设置忽略字段
PropertyMap<HashMap<String,Object>, Ne10mPopulatedPlaces> propertyMap = new PropertyMap<HashMap<String,Object>, Ne10mPopulatedPlaces>() {protected void configure() {skip(destination.getPkId());skip(destination.getGeomJson());}
};
modelMapper.addMappings(propertyMap);

        请注意,这里的忽略字段可以根据项目的需求进行灵活的增减。最后在设置完propertyMap后不要忘了使用addMappings来添加。随后运行程序,经过设置忽略字段后,程序有稍微一点的提僧。处理和转换消耗的时间如下:

解析1807毫秒 转换58988毫秒

        从运行结果可以看到,shapefile的解析时间不多,转换实现有了些许的提升,7771毫秒,将近7秒钟。感觉前途似乎看到了一些希望。

2、设置忽略空值模式

        除了一些指定的字段值可以不用设置之外,还有一些属性是空值的,在转换时其实也是可以不用转换的。因此,第二个优化方法就是忽略空值。关键代码如下:

//设置忽略空值模式
modelMapper.getConfiguration().setSkipNullEnabled(true);

        设置之后再来看一下程序的运行耗时情况。

设置忽略空值模式后耗时: 解析1906毫秒 转换57520毫秒

        来对比一下时间,解析程序的耗时差不多,参数转换的时间又降低了。时间又提升了1468毫秒。提升不是很明显。

3、设置命名模式

        大家知道使用java进行程序开发时,命名方法是有一定的规则的。但是,我们的源对象,比如是HashMap,它的命名可不一定是符合java的命名规范的。比如在map有中一个参数,名字是USER_NAME,而javaBean的属性是userName,所谓驼峰命名方法。因此,通过设置预知的命名模式,也是可以提升一部分性能的。来看一下设置的代码:

//设置命名约定,将下划线转换为驼峰
modelMapper.getConfiguration().setSourceNameTokenizer(NameTokenizers.UNDERSCORE)
.setDestinationNameTokenizer(NameTokenizers.CAMEL_CASE);

        UnderscoreNameTokenizer这里是表示带下划线的转换成驼峰的命名方法,下面来看一下设置命名模式后的转换耗时:

命名模式设置后耗时:解析1895毫秒 转换52895毫秒

        时间消耗又提升了4625毫秒。

4、采用精准匹配模式

        经过之前的几步优化,我们的转换程序依然提升不是很明显,原因是参数和属性进行映射时,还是采用打分然后选取最高分的标准处理模式,那么我们有没有可能使用精准的匹配模式呢?这样就能减少很多的时间消耗。精准匹配模式的设置方法为:

//精准模式
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);

        我们来看一下精准匹配对象类的源码:

        相比于标准的处理处理模式如下图所示:

         可以看到,在match方法中,标准匹配模式比精准匹配模式的转换方法处理更简洁,而且对比匹配时也只是进行equalsIgnoreCase对比值,因此速度很快。下面我们来看一下最终的耗时。

开启精准匹配模式耗时:解析1940毫秒 转换14137毫秒

        到这里,可以看到系统的转换性能得到了极大的提升,现在只需要14137毫秒了。从原来的一分多钟优化到14秒左右。由此可以看出,选用正确的匹配模式对于提升程序的处理时间有巨大的帮助。

四、总结

        以上就是本文的主要内容,本文即以解析全球主要城市数据为例,重点介绍如何一步一步的优化转换策略和逻辑,将对象的转换时间性能提升76%的过程。希望通过本文的介绍,让您对掌握和优化ModelMapper有更深的了解。文章首先介绍ModelMapper的核心对象,然后介绍配置对象和映射引擎。接着分别介绍在默认模式、设置字段忽略、控制忽略、命名匹配、精准匹配模式下的不同转换耗时,通过这几个步骤和设置,就可以对我们的程序进行极大的性能优化。行文仓促,难免有许多不足之处,若有不足,还请各位专家和朋友在评论区留言指正,不胜感激。

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

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

相关文章

【C语言】结构体、联合体、枚举类型的字节大小详解

在C语言中&#xff0c;结构体&#xff08;struct&#xff09;和联合体&#xff08;union&#xff09; 是常用的复合数据类型&#xff0c;它们的内存布局和字节大小直接影响程序的性能和内存使用。下面为大家详细解释它们的字节大小计算方法&#xff0c;包括对齐规则、内存分配方…

【优选算法】位运算

目录 常见位运算总结1、基础位运算2、给一个数n&#xff0c;确定它的二进制位的第x位上是0还是13、将一个数n的二进制位的第x位改成14、将一个数n的二进制位的第x位改成05、位图的思想6、提取一个数n的二进制位中最右侧的17、将一个数n的二进制位中最右侧的1变为08、位运算的优…

jQuery九宫格抽奖,php处理抽奖信息

功能介绍 jQuery九宫格抽奖是一种基于jQuery库的前端抽奖效果。通过九宫格的形式展示抽奖项&#xff0c;用户点击抽奖按钮后&#xff0c;九宫格开始旋转&#xff0c;最终停在一个随机位置上&#xff0c;此位置对应的抽奖项为用户的中奖结果。 本文实现九宫格的步骤为&#xf…

AI界的信仰危机:单靠“规模化”智能增长的假设,正在面临挑战

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Unity类银河战士恶魔城学习总结(P149 Screen Fade淡入淡出菜单)

【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili 教程源地址&#xff1a;https://www.udemy.com/course/2d-rpg-alexdev/ 本章节实现了进入游戏和死亡之后的淡入淡出动画效果 UI_FadeScreen.cs 1. Animator 组件的引用 (anim) 该脚本通过 Animator 控制 UI 元…

【C语言篇】探索 C 语言结构体:从基础语法到数据组织的初体验

我的个人主页 我的专栏&#xff1a;C语言&#xff0c;希望能帮助到大家&#xff01;&#xff01;&#xff01;点赞❤ 收藏❤ 目录 什么是结构体结构体的定义与使用结构体内存布局嵌套结构体与指针结构体数组的操作结构体与函数结构体内存对齐机制位域与结构体的结合动态内存分…

COMSOL工作站:配置指南与性能优化

COMSOL Multiphysics 求解的问题类型相当广泛&#xff0c;提供了仿真单一物理场以及灵活耦合多个物理场的功能&#xff0c;供工程师和科研人员来精确分析各个工程领域的设备、工艺和流程。 软件内置的#模型开发器#包含完整的建模工作流程&#xff0c;可实现从几何建模、材料参数…

大语言模型LLM的微调代码详解

代码的摘要说明 一、整体功能概述 这段 Python 代码主要实现了基于 Hugging Face Transformers 库对预训练语言模型&#xff08;具体为 TAIDE-LX-7B-Chat 模型&#xff09;进行微调&#xff08;Fine-tuning&#xff09;的功能&#xff0c;使其能更好地应用于生成唐诗相关内容的…

qt5.14.2跟vs2022配置

1.qt6要在线安装&#xff0c;安装时间比较长&#xff0c;要求网络要稳定&#xff0c;不适合快速安装 2.使用qt5.14.2离线安装包&#xff0c;安装速度快&#xff0c;可以快速安装。 3.安装完qt.5.14.2后打开QtCreate4.0.1&#xff0c;打开 工具->选项->Kits,发现如下图: 没…

【拥抱AI】RAG(Retrieval-Augmented Generation)知识库的切片策略及其改进

1. RAG简介 RAG是一种结合了信息检索和文本生成的技术&#xff0c;它通过从一个外部的知识库中检索相关信息来增强生成模型的能力。这种方法可以提高生成内容的相关性和准确性&#xff0c;特别是在处理长文档时&#xff0c;有效的文本切片策略对于提升检索效率和质量至关重要。…

webrtc ios h264 硬编解码

webrtc ios h264 硬编解码 一 ios 系统支持 从ios8开始&#xff0c;苹果公司开放了硬解码和硬编码API&#xff08;即 VideoToolbox.framework API&#xff09; 二 主要api 1 主要解码函数 VTDecompressionSessionCreate // 创建解码 session VTDecompressionSession…

深入解析 MySQL 启动方式:`systemctl` 与 `mysqld` 的对比与应用

目录 前言1. 使用 systemctl 启动 MySQL1.1 什么是 systemctl1.2 systemctl 启动 MySQL 的方法1.3 应用场景1.4 优缺点优点缺点 2. 使用 mysqld 命令直接启动 MySQL2.1 什么是 mysqld2.2 mysqld 启动 MySQL 的方法2.3 应用场景2.4 优缺点优点缺点 3. 对比分析结语 前言 MySQL …

Ubuntu20.04运行LARVIO

文章目录 1.运行 Toyish 示例程序2.运行 ROS Nodelet参考 1.运行 Toyish 示例程序 LARVIO 提供了一个简化的toyish示例程序&#xff0c;适合快速验证和测试。 编译项目 进入 build 文件夹并通过 CMake 编译项目&#xff1a; mkdir build cd build cmake -D CMAKE_BUILD_TYPER…

[2024年3月10日]第15届蓝桥杯青少组stema选拔赛C++中高级(第二子卷、编程题(2))

方法一&#xff08;string&#xff09;&#xff1a; #include <iostream> #include <string> using namespace std;// 检查是否为回文数 bool isPalindrome(int n) {string str to_string(n);int left 0, right str.size() - 1;while (left < right) {if (s…

HTML 中 a 标签跳转问题总结:从框架页面跳转的困境与突破

在 HTML 网页开发过程中&#xff0c;a 标签作为超链接的常用标记&#xff0c;其跳转功能看似简单&#xff0c;实则在一些特定场景下会遇到诸多复杂问题。本文将围绕一个具体的案例展开&#xff0c;深入探讨在框架页面中使用 a 标签跳转时所面临的挑战以及相应的解决方案&#x…

【Db First】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列 &#x1f…

课题组自主发展了哪些CMAQ模式预报相关的改进技术?

空气污染问题日益受到各级政府以及社会公众的高度重视&#xff0c;从实时的数据监测公布到空气质量数值预报及预报产品的发布&#xff0c;我国在空气质量监测和预报方面取得了一定进展。随着计算机技术的高速发展、空气污染监测手段的提高和人们对大气物理化学过程认识的深入&a…

扫雷-完整源码(C语言实现)

云边有个稻草人-CSDN博客 在学完C语言函数之后&#xff0c;我们就有能力去实现简易版扫雷游戏了&#xff08;成就感满满&#xff09;&#xff0c;下面是扫雷游戏的源码&#xff0c;快试一试效果如何吧&#xff01; 在test.c里面进行扫雷游戏的测试&#xff0c;game.h和game.c…

uniapp在App端定义全局弹窗,当打开关闭弹窗会触发onShow、onHide生命周期怎么解决?

在uniapp(App端)中实现自定义弹框&#xff0c;可以通过创建一个透明页面来实现。点击进入当前页面时&#xff0c;页面背景会变透明&#xff0c;用户可以根据自己的需求进行自定义&#xff0c;最终效果类似于弹框。 遇到问题&#xff1a;当打开弹窗(进入弹窗页面)就会触发当前页…

【C++】C++新增特性解析:Lambda表达式、包装器与绑定的应用

V可变参数模板与emplace系列 C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类C/C内存管理模板初阶String使用String模拟实现Vector使用及其模拟实现List使用及其模拟实现…