结果集 tostring_关于避免对toString()结果进行解析或基于逻辑的美德

结果集 tostring

使用Java或我使用过的其他编程语言,我发现有时候可以用该语言完成某些事情,但通常不应该这样做。 通常,这些误用语言似乎无害,当开发人员首次使用它们时可能是有益的,但后来同一位开发人员或另一位开发人员遇到了相关的问题,需要克服或改变这些代价。 一个示例(也是本博客文章的主题)是使用Java中toString()调用的结果进行逻辑选择或对其内容进行解析。

在2010年,我用Java语言编写了toString()注意事项 ,当toString()方法可明确用于类时以及当它们包含该类对象的相关公共状态时,我通常会首选它。 我仍然有这种感觉。 但是,我希望toString()实现足以使人们通过记录的语句或调试器读取对象的内容,而不是要由代码或脚本解析的内容。 使用toString()方法返回的String进行任何类型的条件或逻辑处理都非常脆弱。 同样,解析toString()返回的String以获取有关实例状态的详细信息也是脆弱的。 我警告过(甚至是无意间)要求开发人员在前面提到的博客文章中解析toString()结果。

开发人员可能出于多种原因选择更改toString()的生成的String,包括将现有字段添加到以前可能未表示过的输出中,将更多数据添加到已经表示过的现有字段中,为新添加的字段添加文本,删除不再在课程中的字段的表示形式或出于美学原因更改格式。 开发人员还可以更改toString()生成的String拼写和语法问题。 如果toString()提供的String仅由人类在日志消息中分析对象的状态时使用,则除非它们删除了实质信息,否则这些更改不太可能成为问题。 但是,如果代码依赖于整个String或为某些字段解析String ,则可以通过这些类型的更改轻松地将其破坏。

出于说明目的,请考虑以下Movie类的初始版本:

package dustin.examples.strings;/*** Motion Picture, Version 1.*/
public class Movie
{private String movieTitle;public Movie(final String newMovieTitle){this.movieTitle = newMovieTitle;}public String getMovieTitle(){return this.movieTitle;}@Overridepublic String toString(){return this.movieTitle;}
}

在这个简单且有些人为的示例中,只有一个属性,因此类的toString()仅仅返回该类的单个String属性作为类的表示形式并不稀奇。

下一个代码清单包含一个不幸的决定(第22-23行),该决定基于Movie类的toString()方法的逻辑。

/*** This is a contrived class filled with some ill-advised use* of the {@link Movie#toString()} method.*/
public class FavoriteMoviesFilter
{private final static List<Movie> someFavoriteMovies;static{final ArrayList<Movie> tempMovies = new ArrayList<>();tempMovies.add(new Movie("Rear Window"));tempMovies.add(new Movie("Pink Panther"));tempMovies.add(new Movie("Ocean's Eleven"));tempMovies.add(new Movie("Ghostbusters"));tempMovies.add(new Movie("Taken"));someFavoriteMovies = Collections.unmodifiableList(tempMovies);}public static boolean isMovieFavorite(final String candidateMovieTitle){return someFavoriteMovies.stream().anyMatch(movie -> movie.toString().equals(candidateMovieTitle));}
}

尽管有多个电影共用同一标题 ,但尽管存在一些潜在的问题,但该代码似乎仍然可以工作一段时间。 但是,即使在遇到这些问题之前,如果开发人员确定他或她想将Movie.toString()表示形式的格式更改为下一个显示的内容,则可能会意识到在相等性检查中使用toString()的风险。代码清单。

@Override
public String toString()
{return "Movie: " + this.movieTitle;
}

也许更改了Movie.toString()返回值,以使提供的StringMovie类的实例相关联更加清楚。 不管进行更改的原因如何,以前列出的在影片标题上使用相等性的代码现在都已损坏。 该代码需要更改为使用contains而不是equals ,如下面的代码清单所示。

public static boolean isMovieFavorite(final String candidateMovieTitle)
{return someFavoriteMovies.stream().anyMatch(movie -> movie.toString().contains(candidateMovieTitle));
}

当意识到Movie类需要更多信息来使电影与众不同时,开发人员可以将发行年份添加到movie类。 接下来显示新的Movie类。

package dustin.examples.strings;/*** Motion Picture, Version 2.*/
public class Movie
{private String movieTitle;private int releaseYear;public Movie(final String newMovieTitle, final int newReleaseYear){this.movieTitle = newMovieTitle;this.releaseYear = newReleaseYear;}public String getMovieTitle(){return this.movieTitle;}public int getReleaseYear(){return this.releaseYear;}@Overridepublic String toString(){return "Movie: " + this.movieTitle;}
}

添加发行年份有助于区分具有相同标题的电影。 这也有助于将翻拍与原作区分开。 但是,无论电影发行的年份如何,使用Movie类查找收藏夹的代码仍将显示所有具有相同标题的电影。 换句话说,1960年版的《 海洋十一人》 ( 目前对IMDB评分为6.6 )将与2001年版的《 海洋十一人》 ( 目前对IMDB评分为7.8 )一起成为人们的最爱,尽管我更喜欢较新的版本。 同样,1988年提出为电视版后窗 (的5.6评级目前IMDB )将返回为收藏旁边的1954年版后窗 (执导的阿尔弗雷德·希区柯克 ,主演詹姆斯·斯图尔特和格蕾丝·凯莉 ,以及额定8.5目前在IMDB中 ),尽管我更喜欢旧版本。

我认为toString()实现通常应包含对象的所有公共可用细节。 但是,即使将MovietoString()方法增强为包括发行年份,客户端代码也不会基于年份进行区分,因为它仅对电影标题执行contain

@Override
public String toString()
{return "Movie: " + this.movieTitle + " (" + this.releaseYear + ")";
}

上面的代码显示了添加到MovietoString()实现中的发行年份。 下面的代码显示了如何更改客户以正确遵守发布年份。

public static boolean isMovieFavorite(final String candidateMovieTitle,final int candidateReleaseYear)
{return someFavoriteMovies.stream().anyMatch(movie ->   movie.toString().contains(candidateMovieTitle)&& movie.getReleaseYear() == candidateReleaseYear);
}

我想情况下它是一个解析一个好主意,这是很难toString()上的结果,方法或基础条件或其他逻辑toString()方法。 在我考虑的几乎所有示例中,都有更好的方法。 在上面的示例中,最好向Movie添加equals() (和hashCode() )方法,然后对Movie实例使用相等性检查,而不要使用单个属性。 如果确实需要比较各个属性(例如,在不需要对象相等且只需要一个或两个字段相等的情况下),则可以使用适当的getXXX方法。

作为一名开发人员,如果我希望类的用户(通常会最终包括我自己)不需要解析toString()结果或依赖于某个结果,则需要确保我的类使toString()提供任何有用的信息toString()可从其他易于访问且更编程友好的资源中获得,例如“获取”方法以及相等性和比较方法。 如果开发人员不想通过公共API公开某些数据,则很可能开发人员也可能真的不想在返回的toString()结果中公开数据。 Joshua Bloch ( Effective Java)以粗体强调该文本,“……提供对toString()返回的值中包含的所有信息的编程访问。”

Effective Java中 ,Bloch还包括有关toString()方法是否应具有其提供的String表示形式的公告格式的讨论。 他指出,这种表示形式(如果进行广告宣传)必须是从那时起一直使用的,如果它是广泛使用的类,则可以避免我在本文中演示的运行时中断类型。 他还建议,如果不能保证格式保持不变,则Javadoc也应包含与此相关的声明。 通常,由于Javadoc和其他注释经常比我想要的更被忽略,并且由于所宣传的toString()表示形式具有“永久性”,因此我宁愿不依赖于toString()提供客户端所需的特定格式,而是提供一种专用于客户可以调用的方法。 这使我可以灵活地在类更改时更改toString()

JDK中的示例说明了我的首选方法,还说明了将特定格式指定为toString()的早期版本的危险。 BigDecimal的toString()表示在JDK 1.4.2和Java SE 5之间进行了更改,如“ J2SE 5.0中的不兼容性(自1.4.2起) ”所述:“ J2SE 5.0 BigDecimaltoString()方法的行为与早期版本不同版本。” BigDecimal.toString()的1.4.2版本的Javadoc仅在方法概述中声明:“返回此BigDecimal的字符串表示形式。 使用Character.forDigit(int,int)提供的数字到字符的映射。 前导减号用于表示符号,小数点右边的位数用于表示刻度。 (此表示形式与(字符串)构造函数兼容。)” Java SE 5和更高版本中BigDecimal.toString()的相同方法概述文档更加详细。 这样冗长的描述,在此不再赘述。

BigDecimal.toString()是与Java SE 5改变 ,其他的方法被引入本不同String表示: toEngineeringString()和toPlainString() 。 新引入的方法toPlainString()提供了JDK 1.4.2提供的BigDecimaltoString() 。 我倾向于提供提供特定String表示形式和格式的方法,因为这些方法可以具有其名称中描述的格式的细节,并且Javadoc注释以及对类的更改和添加不会像对它们产生影响那样对这些方法产生影响一般的toString()方法。

有一些简单的类可能适合原始实现的toString()方法将一劳永逸地修复且“永远不会”改变的情况。 那些可能是解析返回字符串或在基础逻辑候选String ,但即使在这种情况下,我更喜欢提供一种具有广告和有保证的格式的另一种方法和离开toString()表示一些灵活性变化。 拥有多余的方法没什么大不了的,因为尽管它们返回相同的内容,但多余的方法可以仅仅是调用toString的单行方法。 然后,如果toString()确实发生了变化,则可以将调用方法的实现更改为以前提供的toString() ,并且该额外方法的任何用户都不会看到任何更改。

当将toString()结果解析为逻辑或基于toString()调用的结果逻辑时,最有可能在将特定方法视为客户访问特定数据的最简单方法时进行。 最好通过其他特定的公共可用方法来使数据可用,并且类和API设计人员可以通过确保toString()提供的String中甚至可能有用的任何数据也可以通过编程访问的特定替代方式来提供帮助。方法。 简而言之,我的首选是将toString()一种方法,以查看有关表示形式中实例的一般信息,该实例可能会发生更改,并为表示形式中的特定数据段提供特定的方法,这些数据的更改可能性较小且更容易以编程方式访问决策并基于可能需要特定于格式的解析的大型String进行决策。

翻译自: https://www.javacodegeeks.com/2016/05/virtues-avoiding-parsing-basing-logic-tostring-result.html

结果集 tostring

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

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

相关文章

3制造数据集_基于MBD的产品设计制造技术研究

本篇节选自论文《基于MBD的产品设计制造技术研究》&#xff0c;发表于《中国电子科学研究院学报》第8卷第6期&#xff0c;作者为中国电子科技集团公司第14研究所专家朱建军。本文经授权转载自公众号学术plus&#xff0c;版权归原作者所有。作者&#xff1a;中国电子科技集团公司…

JSP文件如何转换成Java文件?

文章目录jsp 文件如何转换成 java 文件jsp 何时开始编译jsp 编译后的文件存储目录jsp 文件如何转换成 java 文件 html ----> service(),使用 out.write()输出。 java代码片段 <% %> ----> service(),照…

【WebRTC---源码篇】(九)媒体协商

1.媒体协商的过程 2. 重要的接口类 3.时序图 4.几个关键点 5.code if (InitializePeerConnection()) {peer_id_ = peer_id;//参数1:观察者,创建成功后回调OnSuccess//参数2:消息类型,自动推导peer_connection_->CreateOffer(this, webrtc::PeerConnectionInterface::RTCOff…

jpa 使用jdbc_在JPA和JDBC中使用存储过程。 嗯,只要使用jOOQ

jpa 使用jdbcJava杂志的当前版本由Josh Juneau撰写了有关JDBC和JPA的大数据最佳实践的文章&#xff1a; http : //www.javamagazine.mozaicreader.com/MayJune2016 本文介绍了如何在JDBC中使用存储过程&#xff08;不幸的是&#xff0c;请注意如何关闭资源。即使在Java Magazi…

JSP文件中Java代码的几种形式(JSP脚本)

文章目录第一种形式&#xff08;Java 代码片段&#xff09;第二种形式&#xff08;JSP 表达式&#xff09;第三种形式&#xff08;JSP 声明&#xff09;第四种形式&#xff08;JSP 指令&#xff09;第一种形式&#xff08;Java 代码片段&#xff09; 原样复制到 service() 方法…

【WebRTC---源码篇】(七)NACK的处理流程

NACK调用栈 从分发器接收Packet包 void RtpVideoStreamReceiver::ReceivePacket(const RtpPacketReceived& packet) {if (packet.payload_size() == 0) {// Padding or keep-alive packet.// TODO(nisse): Could drop empty packets earlier, but need to figure out how…

java实现资源监视器_实现Java监视的12个步骤程序存在缺陷

java实现资源监视器Java监视的当前状态最大的问题是什么&#xff1f; 生产中的错误很像喝醉的短信。 您只有在事情已经发生之后才意识到出了点问题。 发短信日志通常比应用程序错误日志更有趣&#xff0c;但是……两者可能同样难以修复。 在本文中&#xff0c;我们将执行一个…

QT之QML布局相关总结

使用QML有助于提高界面编写效率&#xff0c;对付界面开发来说&#xff0c;页面如何布局是一个绕不开的点&#xff0c;本文总结一下QML中常用的一些和布局相关的内容。 目录 1.手动定位 2.坐标绑定定位 3.锚定位 4.布局定位器 5.布局管理器 6.其他布局相关 6.1 弹簧功能…

bpmn2 vue 设计器_vue项目中使用bpmn-基础篇

后退前进下载style"display: inline-block;":file-list"fileList"class"upload-demo"action"":auto-upload"false":show-file-list"false":http-request"httpRequest":on-change"handleOnchangeFi…

JSP的隐含对象/隐藏对象/内置对象介绍

文章目录outJspWriter 和 PrintWriter 的区别requestresponsesessionapplicationexceptionconfigpageContextpageContext 的作用绑订数据获得其它几个隐含对象page四个 JSP 域对象访问范围比较out out 对象是 javax.servlet.jsp.JspWriter 类的实例&#xff0c;用来在 respons…

hystrix应用 博客_使用Hystrix DSL创建弹性骆驼应用程序

hystrix应用 博客Apache Camel是一个成熟的集成库&#xff08;到现在已有9年的历史了&#xff09;&#xff0c;它实现了Enterprise Integration Patterns一书中的所有模式。 但是Camel不仅是EIP实现库&#xff0c;它还是一个不断发展&#xff0c;添加新模式并适应行业变化的现代…

notebook打开外部文件_CAD外部参照真是个好东西!

好课推荐&#xff1a;零基础CAD&#xff1a;点我CAD室内&#xff1a;点我 周站长CAD&#xff1a;点我CAD机械&#xff1a;点我 Bim教程&#xff1a;点我CAD建筑&#xff1a;点我CAD三维&#xff1a;点我全屋定制&#xff1a;点我 ps教程&#xff1a;点我苹果版CAD:点我 3dmax教…

JSP动作元素/活动元素

文章目录jsp:forwardjsp:includejsp:paramjsp:useBeanjsp:setPropertyjsp:setProperty name"" property"" value""jsp:setProperty name"" property"" param""jsp:setProperty name"" property"*&…

【数论系列】任意角的三角函数

角度转为弧度 import math math.radians(x) 弧度转为角度 import math math.degrees(x) 正弦函数 import math math.sin(弧度) 余弦函数 import math math.cos(弧度) 正切函数 import math math.tan(弧度)

gradle groovy_适用于Java开发人员的Groovy吗? 认识Gradle,Grails和Spock

gradle groovyJava开发人员最感兴趣的Groovy用例有哪些&#xff1f; 尽管已经有一段时间了&#xff0c;但似乎只有Groovy最近才开始使用Groove。 对于某些人来说&#xff0c;它基本上只是另一种深奥的JVM语言&#xff0c;但是由于一些流行的工具可以帮助您使用Java&#xff0c…

JSP 指令元素

文章目录page 指令import 属性pageEncoding 属性contentType 属性session 属性isELIgnored 属性errorPage 属性isErrorPage 属性include 指令file 属性taglib 指令uri 属性prefix 属性jsp 源文件转换成对应的 .java 文件时&#xff0c;jsp 的指令会影响 Java 源代码的生成&…

Python日常工具 ----- 读取Excel表格下载MP3

import xlrd import os import requestsdef GetList():worksheet xlrd.open_workbook(01.xlsx)sheet_names worksheet.sheet_names()print(sheet_names)for sheet_name in sheet_names:sheet worksheet.sheet_by_name(sheet_name)rows sheet.nrows # 获取行数cols sheet.…

indesign中调出字符样式快捷键_Word中十大黄金快捷键,你会用几个?

在使用Word文档时&#xff0c;熟练使用快捷键能够有效的提升我们的工作效率&#xff0c;但是&#xff0c;Word中快捷键也比较多&#xff0c;要想全部掌握&#xff0c;那不太现实&#xff0c;这里&#xff0c;易老师给大家挑选了10组黄金快捷键&#xff0c;非常实用。01 快速移动…

couchbase集群_使用CLI扩展和重新平衡Couchbase集群

couchbase集群Couchbase通过多种方式提供高可用性和灾难恢复 &#xff1a; 同质簇 复写 集群内复制 备份还原 机架区意识 该博客将展示如何使用Couchbase命令行界面&#xff08;CLI&#xff09;创建Couchbase集群。 此外&#xff0c;还可以使用Couchbase REST API和Couchba…

【音视频安卓开发 (十)】jni开发中将java中的buffer映射到native c++中

首先在java层定义一个buffer,并且开辟相应的内存空间 private ByteBuffer byteBuffer; byteBuffer ByteBuffer.allocateDirect(bytesPerFrame * framesPerBuffer ); 然后调用本地的方法来设置内存地址到native层&#xff0c;该方法在jni初始化时就已经被动态的注册了方法,注…