关于避免对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)提供的数字到字符的映射。 前导减号用于表示符号,小数点右边的位数用于表示刻度。 (该表示法与(String)构造函数兼容。)” 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

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

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

相关文章

NYOJ90 整数划分(经典递归和dp)

整数划分 时间限制&#xff1a;3000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;3描述将正整数n表示成一系列正整数之和&#xff1a;nn1n2…nk&#xff0c; 其中n1≥n2≥…≥nk≥1&#xff0c;k≥1。 正整数n的这种表示称为正整数n的划分。求正整数n的不 同划分个数。…

昆士兰科技大学计算机专业,昆士兰科技大学QUT计算机科学Computer Science专业排名第101-125位(2021年THE世界大学商科排名)...

2021年THE泰晤士高等教育计算机科学Computer Science专业世界大学排名公布&#xff0c;昆士兰科技大学QUT计算机科学世界排名第101-125位&#xff0c;昆士兰科技大学QUT计算机科学专业实力怎么样呢&#xff1f;下面美英港新留学介绍昆士兰科技大学QUT计算机科学专业培养计划&am…

不要讨厌HATEOAS Part Deux:HATEOAS的春天

在我关于HATEOAS的系列文章的最后结论中&#xff0c;我们将深入探讨如何使用Spring-Data-REST和Spring-HATEOAS实现HATEOAS。 HATEOAS的春天到了&#xff01; 我整理了一个有效的项目&#xff0c;该项目将演示下面的代码示例以及其他一些功能。 该项目可以在这里找到&#xff…

linq内联左联

内联&#xff1a;没有into 左联&#xff1a;有into 例子&#xff1a; from GoodsStore in this.GetCurrentDbSession.Tbl_OfficeSupplies_GoodsStoreDLL.LoadEntities(a > (Guid.EmptyGoodsID?true:a.GoodsIDGoodsID)) join goods in GetCurrentDbSession.Tbl_OfficeSuppli…

计算机操作员实操高级试题,计算机操作员高级实操(以往考过,可做平时练习素材)答题.doc...

试题1、计算机安装、连接、调试试题2、文字录入b)中文基本录入&#xff1a;在十分钟之内录入以下中文内容&#xff0c;错误率不高于千分之三。c)公式录入&#xff1a;在文档的结尾处录入下列公式。d)完成以上操作后&#xff0c;将最终结果以“高级2-1.doc”为文件名&#xff0c…

ls 显示目录下的内容和文件相关属性信息

1.命令功能 ls命令是“list directory contents”&#xff0c;显示当前目录下的内容和文件属性。 2.语法格式 ls [option] file ls 选项 文件名 3.选项说明 参数 参数说明 -a 显示全部文件包括隐藏文件&#xff0c;包括.和.. -A 显示全部文件&#xff0c;但是不包括.和…

计算机休眠下睡眠的不同点是什么,电脑的关机选项里,休眠和睡眠有什么具体的区别呢?...

电脑的关机选项里&#xff0c;休眠和睡眠有什么具体的区别呢&#xff1f;以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;电脑的关机选项里&#xff0c;休眠和睡眠有什么具体的区别呢&#x…

maven jpa_使用Hibernate 4,JPA和Maven的架构创建脚本

maven jpa这种情况很简单–您想要在构建应用程序时生成数据库模式创建脚本&#xff08;然后在目标数据库上执行脚本&#xff09;&#xff0c;这在Hibernate 3中相对容易&#xff0c;因为有 hibernate3-maven-plugin &#xff0c;但是与Hibernate 4不兼容。当然&#xff0c;对于…

读取带空格字符串小结

1 &#xff0c;gets() 可以无限读取&#xff0c;以回车结束读取&#xff0c;C语言中的函数&#xff0c;在C中运行会产生bug。 如&#xff1a; #include <iostream> #include <cstdio> using namespace std; int main() { chara[50]; cin>>a; gets(a); cout&l…

计算机x线摄影的发展趋势,计算机X线摄影技术----CR 新进展

结构化存贮荧光体(针状成像板)(Structured Storage Phosphors(Needle ImagePlates))结构化荧光体&#xff0c;也就是各向异性物理结构&#xff0c;已经存在很久&#xff0c;且已得到广泛应用&#xff0c;比如在影像增强管中吸收X线&#xff0c;并将射线激励的可见光导入成像链的…

开发一个智能问答机器人(优化篇)

上一篇介绍了整个问答机器人的技术架构和特定&#xff0c;本篇着重说下 如何让机器人&#xff08;看起来&#xff09;更智能 输入联想 使用jquery.autosuggest.js实现的输入联想&#xff0c;在输入2个字后&#xff0c;在5000个问答中基于全文检索&#xff0c;检索10条记录&…

使用Java将项目插入DynamoDB表

在上一篇文章中&#xff0c;我们学习了如何使用Java创建DynamoDB表。 下一步是将项目插入到先前创建的DynamoDB表中。 请记住&#xff0c;对于插入操作&#xff0c;最基本的步骤是指定主键。 对于表用户&#xff0c;主键是属性电子邮件。 您可以根据需要添加任意数量的属性&am…

计算机vb操作题评分细则,上机考试的试题及评分标准.doc

上机考试的试题及评分标准上机题总分占40分&#xff0c;其中改错题占14分&#xff0c;编程题占26分。(1)改错题&#xff1a;题目中都是设3个错误点(在历年上机考题中也出现过只有2个错误点的试题)&#xff0c;一般分别是语法错误(如数组的声明、重复定义等略有难度的语法错误)、…

面试汇总

HTML部分 1.HTML5新特性&#xff0c;语义化 可以参考 https://blog.csdn.net/qq_26562641/article/details/54669288 2.浏览器的标准模式和怪异模式 可以参考 http://www.cnblogs.com/zzgyq/p/8630709.html 3. xhtml和html的区别 XHTML 元素必须被正确地嵌套…

64 合并排序数组

原题网址&#xff1a;http://www.lintcode.com/zh-cn/problem/merge-sorted-array/# 合并两个排序的整数数组A和B变成一个新的数组。 注意事项 你可以假设A具有足够的空间&#xff08;A数组的大小大于或等于mn&#xff09;去添加B中的元素。 您在真实的面试中是否遇到过这个题&…

Ios9 html5,ios9,html5_ios9下在浏览器中通过scheme打开app的问题,ios9,html5 - phpStudy

ios9下在浏览器中通过scheme打开app的问题ios9系统下&#xff0c;safari下通过iframe(scheme)的方式跳app&#xff0c;无法打开app&#xff0c;通过location.hrefscheme的方式倒是可以&#xff0c;不过在没有安装app时&#xff0c;这种方式可能会直接跳转到一个错误页面(无法打…

使用Spring Boot进行面向方面的编程

在上一篇文章中&#xff0c;我提供了一个有关如何通过使用ProxyFactoryBean并实现MethodBeforeAdvice接口在Spring实现宽高比定向的简单示例。 在此示例中&#xff0c;我们将学习如何通过使用Spring Boot和Aspect4j注释来实现方面方向。 让我们从gradle文件开始。 group com…

java中的单例模型

参考网址:http://www.runoob.com/design-pattern/singleton-pattern.html 1.目的:保证一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点。(比如世界只有一个月亮,党只有一个主席) 2. 优点&#xff1a; 1、在内存里只有一个实例&#xff0c;减少了内存的开销&#x…

计算机电路基础张志良,计算机电路基础

图书简介配套资源&#xff1a;电子课件本书特色&#xff1a;★ 金牌作者编写&#xff0c;专门针对计算机专业设计教学内容★ 内容广、难度浅、适用面宽★ 配有《学习指导与习题解答》(ISBN 978-7- 111- 35112-2)本书配套资源&#xff0c;样书均可在本页下载申请&#xff0c;也可…

Java-变量函数 上

类的组成&#xff08;三部分&#xff09;全局变量&#xff08;成员变量&#xff09;和局部变量成员方法&#xff08;函数&#xff09;变量按照变量的数据类型分类基本数据类型 字符型 布尔 整型 浮点型引用数据类型 String 数组根据变量定义的位置不同&#xff08;或者…