开发工具分享
  • 首页
  • 计算科学
  • 文化旅游
  • 项目和网站
    • OSSEZ 计算技术
    • USRealEstate 社区
    • 地区文化
    • CWIKI.US
    • BUG.OSSEZ.COM
    • RSS.OSSEZ.COM
CWIKIUS.CN
一个有独立思考和温度的清新站
Computer Science

理解 Java 中的 NumberFormatException 异常

如果我在 Java 中对字符串和数字直接进行类型转换的话,我们有可能会遇到 NumberFormatException 异常。 介绍 当 Java 在将 String 字符串转换为数字的时候,如果遇到没有办法转换的情况,Java 将会抛出一个 NumberFormatException 异常。 NumberFormatException 这个异常是 Java 中的一个 unchecked 类型异常,因此程序不会被要求强制进行处理。 在本页面中,我们对 NumberFormatException 这个异常进行一些简要说明和我们应该如何避免这个异常。 如何导致 NumberFormatException 异常的 在实际编码过程中,有一些构造方法或者类型转换方法,将会导致这个异常。 对导致这个异常的常见情况,我们在下面的页面中进行一些说明和讨论。 构造函数中 如果我们在构造函数中对不是数字的字符串进行类型转换的话,将会有可能抛出这个异常。 例如我们尝试将一个字符串转换为 Integer 或Double 对象,但是输入的字符串不是数字。 下面 2 个句子将会抛出 NumberFormatException 异常: Integer aIntegerObj = new Integer("one"); Double doubleDecimalObj = new Double("two.2"); 我们如果运行上面的代码,我们可以看到 JDK 将会提示我们没有办法将输入的字符串转换为整数类型。 Exception in thread "main" java.lang.NumberFormatException: For input string: "one" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.lang.Integer.parseInt(Integer.java:580) at java.lang.Integer.<init>(Integer.java:867) at MainClass.main(MainClass.java:11)     上面的构造方法将会抛出无法将字符串转换为数字的异常。 在调用 parseInt() 内部方法的时候将会提示无法转换的错误。 上面的修改也非常简单,这是因为 Java 的 Number API 不能处理字符串导致的,我们只需要将输入的字符串进行调整,保持为数字类型即可。 使用下面的代码就没有问题了。 Integer aIntegerObj = new Integer("1"); Double doubleDecimalObj = new Double("2.2"); 处理非数字类型的方法 与构造方法的错误类似,有些方法在处理的时候也会导致异常。 比如说我们常常会用到的下面的一些方法 par seInt(), parseDouble(), valueOf(), 和 decode() 。 例如,我们尝试进行下面的一些类型的转换的话,我们有可能遇到与上面相同的方法: int aIntPrim = Integer.parseInt("two"); double aDoublePrim = Double.parseDouble("two.two"); Integer aIntObj = Integer.valueOf("three"); Long decodedLong = Long.decode("64403L"); 这个错误与在上面构造方法中出现的错误是相同的。 我们可以简单的按照错误提示修改输入参数就可以了: int aIntPrim = Integer.parseInt("2"); double aDoublePrim = Double.parseDouble("2.2"); Integer aIntObj = Integer.valueOf("3"); Long decodedLong = Long.decode("64403"); 输入字符串参数有一些奇怪字符 另外,不仅仅是输入字符串本身不是数字的问题,有可能输入的字符串可能有一些奇怪的字符,包括有空格,下划线等。 类型转换函数或者构造函数,本身是不会对输入字符串进行处理的。 Short shortInt = new Short("2 "); int bIntPrim = Integer.parseInt("_6000"); 上面我们代码执行的时候也会遇到相同的问题。 例如第一行代码的主要原因就是因为有空格,我们可以首先对空格进行清理。 针对这种情况,我们首先需要对输入的字符串进行格式化处理,处理掉错误的字符。 Short shortInt = new Short("2 ".trim()); int bIntPrim = Integer.parseInt("_6000".replaceAll("_", "")); int bIntPrim = Integer.parseInt("-6000"); 需要注意的是,上面代码中的第 3 行,我们给出的是一个负数。 在 Java 中,负数是允许的,但是你不能使用下划线,你只能使用中划线。 语言特性的数字格式化 这里我们说的语言特性数字格式化主要是因为不同地区和国家对数字的表达方式是不一样的。 例如,在一些国家 “4000,1 ” 可能也会被用来表示一个小数“4000.1”。 如果你不对你的程序进行配置的话,在默认情况下,你还是会得到一个 NumberFormatException 异常,因为我们的程序没有办法处理以逗号表示为小数点: double aDoublePrim = Double.parseDouble("4000,1"); 因此,我们需要让我们的程序明白,这里的逗号是小数点才能避免这个类型转换错误。 例如,我们可以使用 NumberFormat 将数字处理的地区设置为欧洲地区,那么你的程序将不会提示格式字符的错误。 请考察下面的代码,我们设置为法国以后,就可以运行了: NumberFormat numberFormat = NumberFormat.getInstance(Locale.FRANCE); Number parsedNumber = numberFormat.parse("4000,1"); assertEquals(4000.1, parsedNumber.doubleValue()); assertEquals(4000, parsedNumber.intValue()); 最佳实践 让我们来看看有可能导致 NumberFormatException 异常的一些原因,和我们应该如何来应对: Java Number API 不能处理特殊字符,因此不要尝试转换特殊字符。 你可以使用正则表达式对需要转换的字符串中的特殊字符进行过滤。 对需要转换的字符串进行一些处理,包括删除空格和对特殊字符串进行替换,删除等。 在一些特定的情况下,我们还是可以对特殊字符串进行处理的,这个时候你可以使用 NumberFormat 来先进行标记格式。 使用工具类,例如 NumberUtils.isNumber() 先对字符串进行检查。 总结 在这个页面中,我们对将 String 格式化为数字类型,使用 Java Number API 的方法和可能出现的异常进行了一些说明。 在这里我们看到了常见的导致异常的原因和我们可以避免的办法。   https://www.ossez.com/t/java-numberformatexception/13986

2022年08月03日 0Comments 539Browse 0Like Read more
Computer Science

Java 通过构造函数初始化 Integer 对象的方法将会被丢弃

通常,我们可以使用构造方法来创建一个整数对象,例如下面的代码: Integer aIntegerObj = new Integer("1"); 但是,上面的代码有可能在 IDE 中提示将会被丢弃。     将要被丢弃的原因是: Deprecated It is rarely appropriate to use this constructor. Use parseInt(String) to convert a string to a int primitive, or use valueOf(String) to convert a string to an Integer object. 简单来说这个使用这个构造方法创建整数对象的情况并不常见,所以 JDK 就打算丢弃掉这个构造方法创建整数对象的方法了。 可以使用 parseInt(String) 或者 valueOf(String) 来进行类型转换。 简单来说就是这个方法用到的情况并不多,并且不建议使用这个方法来创建新的数字类型对象了。 应该使用类型转换的方法来进行初始化。   https://www.ossez.com/t/java-integer/13987

2022年08月03日 0Comments 483Browse 0Like Read more
Computer Science

Discourse 支持中文用户名

Discourse 在默认安装的情况下是不支持中文用户名的输入的。 根据官方的说明,从 Discourse 2.3.0.beta9 版本开始,Discourse 就已经能够支持 Unicode 的用户名了,包括中文的用户名。 官方发布的文章为:https://meta.discourse.org/t/unicode-usernames-and-group-names/117737。 你需要对你的 Discourse 进行设置就行了。 设置位置 在管理员控制的设置中,搜索字符 unicode。 你就可以看到有个选项叫做 unicode usernames。 选择上这个选项就可以了。     如果你使用的是英文版语言的 Discourse 的话。 那么这个的配置选项就在这里了。     曾经在很久之前,有人讨论过这个内容,不过这个是在官方不支持的情况下。 目前你已经不需要安装这个插件了。   https://www.ossez.com/t/discourse/13983

2022年08月03日 0Comments 504Browse 0Like Read more
Computer Science

Git 如何从特定的提交中创建一个新的分支

有时候我们希望找到一个提交历史,然后从这个提交历史中创建一个分支。 很多人应该都会使用命令行工具来做,其实 IDEA 已经帮你做了。 IDEA 首先在 IDEA 中找到 Git,然后找到你的提交历史。 在找到提交历史后,可以选择鼠标的右键。 然后选择新分支。 你就可以从当前的提交历史中来创建一个新的分支了。 Source Tree 使用 SourceTree 也是一样的。 通过在提交历史中单击右键,然后选择分支,你就可在当前指定的提交历史中来创建一个新的分支了。 https://www.ossez.com/t/git/13981

2022年08月03日 0Comments 718Browse 0Like Read more
Computer Science

Maven 跳过测试的几种方式

在 Maven 对项目进行编译的时候,我们通常可能会希望跳过复杂的测试。     尤其是在开始项目还不是非常稳定的阶段。 命令行中使用 -Dmaven.test.skip=true 在命令行,只要简单的给任何目标添加 maven.test.skip 属性就能跳过测试: mvn install -Dmaven.test.skip=true 命令行中使用 -DskipTests 在 Maven 的命令中,使用参数 -DskipTests 来跳过测试 使用的命令为: mvn install -Dmaven.test.skip=true 修改 POM 文件 在pom.xml文件中增加配置 <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <skip>true</skip> </configuration> </plugin> </plugins> </build> maven.test.skip 和 skipTests 的区别 -DskipTests,不执行测试用例,但编译测试用例类生成相应的class文件至target/test-classes下。 -Dmaven.test.skip=true,不执行测试用例,也不编译测试用例类。 简单来说,这 2 个参数的区别就是 -Dmaven.test.skip 这个参数跳过测试更加彻底,连测试类编译都不会编译。 如果不是非常糟糕的环境配置问题还是其他需求的话,测试类最好还是进行编译。因此使用 -DskipTests 参数。   https://www.ossez.com/t/maven/11034

2022年08月03日 0Comments 420Browse 0Like Read more
Computer Science

JDK 15 以上版本的字符串块

考察下下面的代码: public String textBlocks() { // THIS ONLY FOR JDK 15 return """ Get busy living or get busy dying. --Stephen King"""; } 我们可以看到上面的代码使用了 2 个引号 " 来表示一个字符串的块。 结论 上面的代码只能在 JDK 15 以上的版本才可以使用。 如果你使用的是 JDK 13 或者 14 的版本,你可以开启使用预览模式来让编译器通过。 因为我们的本地使用的是 JDK 11 编译器,上面的字符串表示方式在你的编译器上面会提示错误。   https://www.ossez.com/t/jdk-15/13979

2022年08月03日 0Comments 421Browse 0Like Read more
Computer Science

Java 8 中的设计模式策略

概述 在本篇文章中我们对可以在 Java 8 中的设计模式策略(strategy design pattern)进行一些简单的说明。 如果你对 Java 的设计模式不是非常清楚的话,可以先自行脑补下。 我们简单的总结就是将以前 Java 使用的接口和实现的设计模式,在 Java 8 中可以使用 lambda 函数来进行简化。 在下面内容中,我们首先提供了一个简单的设计模式样例,以及在传统的环境下我们是怎么实现这个设计模式的。     随后,我们将会使用 Java 8 中的 lambda 函数来进行实现,然后介绍一些有什么不同的地方。 模式策略 所谓的模式策略(strategy pattern)的定义就是能够让我们的程序在运行时(runtime)改变算法的表现。 在通常的情况下,我们会首先设计一个接口,然后在这个接口中定义我们需要使用的方法,然后使用不同的类来实现我们的接口定义的方法。 这种设计模式为我们在 Java 面向对象设计时候经常用到的。 让我们来考察下面的一个使用案例,针对不同的节日,我们针对某一个销售使用不同的定价策略,比如说圣诞节(Christmas),复活节(Easter)或者新年(New Year),我们使用的价格策略是不一样的。 首先我们需要在接口中定义一个 Discounter 方法,然后针对不同的节日来实现 Discounter 这个方法。 public interface Discounter { BigDecimal applyDiscount(BigDecimal amount); } 然后我们的目标是在复活节的时候打 5 折(50%),另外一个目标是在圣诞节的时候打 9 折(10%)。 随后我们就可以在下面的 2 个类中实现我们在接口中定义的方法。 public static class EasterDiscounter implements Discounter { @Override public BigDecimal applyDiscount(final BigDecimal amount) { return amount.multiply(BigDecimal.valueOf(0.5)); } } public static class ChristmasDiscounter implements Discounter { @Override public BigDecimal applyDiscount(final BigDecimal amount) { return amount.multiply(BigDecimal.valueOf(0.9)); } } 然后,我们在实现中使用这个策略: Discounter easterDiscounter = new EasterDiscounter(); BigDecimal discountedValue = easterDiscounter .applyDiscount(BigDecimal.valueOf(100)); assertThat(discountedValue) .isEqualByComparingTo(BigDecimal.valueOf(50)); 上面这个设计模式是我们在通常情况下使用的,但是比较头痛的是针对每一个方法,你需要在实现中都实现你需要的方法。 另外一个解决方案就是使用内部类型,但是这个内部类型并没有有太多的提高,你还是有不少的工作需要做。 例如下面使用内部类型的实现: Discounter easterDiscounter = new Discounter() { @Override public BigDecimal applyDiscount(final BigDecimal amount) { return amount.multiply(BigDecimal.valueOf(0.5)); } }; 使用 Java 8 如果你开始使用 Java 8 的话,我们知道 lambda 函数表达式可以做内部类型来使用,这样能够明显的降低多余的代码。 同时会让我们的代码看起来更加整洁和可读。 不管怎么样,使用 lambda 表达式提供了另外一种模式的实现,针对最开始的实现来说,Java 8 的实现提供了更多的一种选择。 降低代码的冗余 现在我们针对 EasterDiscounter 的实现,我们现在只是用 lambda 表达式来实现: Discounter easterDiscounter = amount -> amount.multiply(BigDecimal.valueOf(0.5)); 通过上面的代码,我们可以看到使用 lambda 表达式的实现看起来更加整洁,代码更加可读和便于维护,针对开始使用多行才能实现的内容,现在只需要使用一行就可以完成了。 更主要的是: ** 一个 lambda 表达式可以被用来替换匿名的内部类型**。 如果我们需要对多个折扣力度进行实现的话,使用 lambda 表达式就看起来更加漂亮了: List<Discounter> discounters = newArrayList( amount -> amount.multiply(BigDecimal.valueOf(0.9)), amount -> amount.multiply(BigDecimal.valueOf(0.8)), amount -> amount.multiply(BigDecimal.valueOf(0.5)) ); 如果我们需要对很多折扣力度进行定义的话,我们可以在 Java 8 中使用静态方法,然后这个定义将会在一个类中完成。 如果你愿意的话,Java 8 甚至可以让你在接口中定义静态方法。 对比在实体类和匿名内部类型之间进行选择,让我们在一个单独类中创建多个静态 lambda 表达式: public interface Discounter { BigDecimal applyDiscount(BigDecimal amount); static Discounter christmasDiscounter() { return amount -> amount.multiply(BigDecimal.valueOf(0.9)); } static Discounter newYearDiscounter() { return amount -> amount.multiply(BigDecimal.valueOf(0.8)); } static Discounter easterDiscounter() { return amount -> amount.multiply(BigDecimal.valueOf(0.5)); } } 通过上面的代码,我们可以看到使用了较少的代码,我们实现了很多的功能。 改进方法的创建 让我们来对 Discounter 接口再次进行修改,这次我们让 Discounter 接口继承 UnaryOperator 接口,然后添加一 combine() 方法: public interface Discounter extends UnaryOperator<BigDecimal> { default Discounter combine(Discounter after) { return value -> after.apply(this.apply(value)); } } 最开始的设计就是通过对 Discounter 接口的调整,能够让 Discounter 接口能够对折扣进行处理。 随着 UnaryOperator 接口被继承,我们可以使用 UnaryOperator 接口提供的 apply() 方法,我们只需要对 applyDiscount 进行替换就可以了。 combine() 方法为在 Discounter 接口中应用的一个抽象,使用一个内建的 apply() 函数来实现。…

2022年08月03日 0Comments 456Browse 0Like Read more
Computer Science

美国房地产经纪人更要注意和我经历的 “杀猪盘” 诈骗

通常房地产经纪人的信息都比较公开,因此不少骗子可能会利用你的信息对你进行诈骗。 作为地产经纪,已经遇到了多起这种诈骗方式。     本篇文章主要对遇到的杀猪盘诈骗进行一些解读,希望大家都能提高警惕,保护自己的资产。 骗子的套路不断升级,最新的手法就是在北美超级流行的“杀猪盘”骗局,在美华人惨被瞄准,可恨的不只是骗钱,同时还诛心! 杀猪盘 “杀猪盘(killing pig plate)”原本是流传在东南亚地区的诈骗方式,如今已席卷全球,诈骗分子将受害者称为“猪”,把交友工具成为“猪槽”、把聊天剧本称为“猪饲料”、把恋爱聊天过程称为“养猪”、把最后诈骗钱财称为“杀猪”。 本来这个诈骗多是针对未婚人士,通常房地产经纪人的警惕性比较高,并且大部分是按照规矩出牌,因此通常不那么容易上钩。 但是,诈骗罪者会伪装为客户,先和你套近乎,然后再一步一步的引导你上钩。 诈骗套路 作为房地产经纪的你肯定会收到不少陌生人的短信,咨询投资买房的事。 正直的你可能会表示,没有适合投资赚钱的房产,而且劝说对方不要和“自住人”抢房产。说到这里,对方便不再和你聊房地产的事,开始吹嘘自己投资有多么厉害,话里话外都是劝说或者诱导你和他一起做投资。 获得你的信任 对方套路的第一步就是,告诉你他/她将会要在某个地方投资一个房地产,为了将诈骗份子包装成成功人士,投资的房产项目通常都在百万上下。 如果你你是资深地产经纪的话,通常你不会在意对方投资多少钱。 虽然对方投资的钱越多,你成交后的收益越多,但是你需要知道,假设你所在地方的成交中位数在 50 万的话,希望投资百万的客户,对自己的需求是非常明确的,同时美国的金融监管机构对购房资金的来源是有要求的,不是说随便什么资金都可以买的。 点评: 为了获得你的信任,通常骗子都会将自己包装成成功人士。 为了对应上面的称呼,骗子通常都会用比较成功人士的照片,照片看起来会让你感觉气质非常不错,有点意思的感觉。 获得你的信息 通常因为房地产经纪人都是为客户服务的。 第一步大部分人都会被攻陷。在被杀猪之前,我们还有多重方法识破的,别着急,只要不到最后一步都没有问题。 骗子在完成第一步以后,将会进行下一步,在这一步中,通常会要求你提供更多的信息。 针对 Agent 来说,骗子会要求你提供一些房源给他们,因为他们要伪装成购房者,如果连房子都不看的话他们就太假了。 作为 Agent 的你,现在应该马上去给对方找房源去了,通常你会按照对方要求找到一些房源,但是对方可能没有办法回复太多信息给。或者对方不会马上回复你。 通常在过了 1 天或者一段时间后,对方会告诉你他对这个房子感觉非常好,然后让你进行一些介绍。 这个时候 Agent 会非常热情的进行介绍,然后对方就会说他感觉也不错。但是有问题就是资金。 骗子会说他的资金大量在虚拟货币中,骗子就问你有没有什么办法。 骗子也会说,我有一些资金在虚拟货币中,并且都是我投资虚拟货币赚钱的,有可能会暗示的问 Agent ,你有没有进行投资呀,有没有进行虚拟货币投资呀。 点评: 不管骗子使用什么手段,最终的目的就是将被骗者往虚拟货币上转。 通过一些问题,骗子可以摸清的底细,对投资的敏感程度,有多少贪念。 因为有前面的铺垫,这个时候你大脑的反应可能没有那么快的与诈骗联系在一起。 暗示或者提示你开户 到这一步的时候,骗子通常会非常诱惑的提示你进行虚拟货币交易所的开户了。 这个时候使用的交易所都是相对正规的,你的开户需要完成身份验证等操作。 如果不是高级骗子,他们会使用自己的网站,这种网站只要有基本的计算机技术知识都能识别。因为这类交易所的网站地址通常都很奇怪,并且成立时间很短。 如果骗子比较高级,这一步他们会诱导你到正规的虚拟货币交易所进行注册。 点评: 只要不是你自愿想了解虚拟货币的开户都有可能是诈骗。 在对虚拟货币不是非常了解的情况下,不要进入虚拟货币领域,控制住自己的欲望,比特币的钱不是那么好赚的。 暗示或者提示你转账 骗子在这个时候将会暗示或者提示你进行转账。 骗子通常会提示你使用电汇的方式,而不是使用其他的方式。 在美国,通常的转账方式是支票,电汇,ACH 扣款,Paypal 等。电汇方式是所有转账方式中转账资金没有上限的转账方式。 Paypal 和支票通常都会有限制。在美国金融系统中,如果你使用支票进行转账,在超过一定金额后,支票的清账时间很长。 例如 Chase 银行,如果你存入个人支票,如果是新用户,清账时间长达 30 天。 Paypal 通常也只用于小额,通常也在 1 千以内。 为了刺激你,骗子会告诉你,因为你没有及时转账,你损失了多少多少。 如果一次不行,骗子会多次刺激你,2 次,3 次,甚至 10 次都不奇怪。但是所有的目的就只有一个就是然后尽快进行电汇。 点评: 如果你对美国的金融和交易系统有所了解的话,你就不会轻易使用电汇的转账方式。 美国的转账方式有很多种,使用电汇方式是比较麻烦的一种方式。 骗子可能会提示你去银行直接电汇。当然你也可以使用手机方式转账,如果使用手机电汇,通常银行自身会有监管,电汇金额过大的话,账号会被冻结直到解除冻结。 这就是为什么骗子一直催你去银行直接电汇。 一个原则,不管在任何时候,任何地方,任何人,如果你对对方不熟悉,不要转账,不要转账,不要转账。 重要的事情说三次。 杀猪 如果你转账成功了,很不幸你就进入了对方的杀猪盘中了。 在这个时候,对方会一步一步诱导你投入更多资金,甚至让你不惜借贷的投入资金。 如果你还保有一点点理智的话,你还是能够及时或者全部止损的。 点评: 人性的特点已经被骗子利用到了极致。 对你不确定的时候,你可以选择和家人和朋友多沟通下,问下他们的看法。 上网搜索下有没有这种类似的诈骗案例,都会有很多办法止损的。 总结 电信诈骗非常可恶,而且损失的资金绝大部分没有办法追回。 其实也不是没有破解的办法,只是非常明确的一点不要被别人带着走,不要怕得罪人,不要怕损失钱。 骗子通常就利用上面几个人性的弱点了一步一步占领你的。 只要提高警惕相信,相信骗子绝对是无从下手的。 除了“杀猪盘”之外,其他的电信诈骗我们也要小心。电信网络诈骗手法千变万化,但万变不离其宗,最后都会要你转账。 最后的防线就是对不熟悉的人:不要转账,不要转账,不要转账。 不管是对方让你转出,还是转入。 对不明确的转账需求,找朋友,家人多核实,总有一个人能想明白的。 下面的一些办法也许能够帮助到你: 来路不明的链接不点。在点链接之前看看链接的地址,短连接,不熟悉的网站直接删除,不管里面的内容多诱人。 没有一夜暴富的神话,所有的钱都不好赚,虚拟货币更是如此。所有诱导进行虚拟货币投资收益的信息都不可信,更不要尝试进行交易。 陌生电话和短信,一定担心。如果不确定一定要多和家人朋友沟通,知道的人越多出问题的情况越少。 控制住自己的欲望,保护好自己的隐私。 多了解一些常见的诈骗手段,对骗子可能会用到的诈骗方式有所了解。电信诈骗其实离我们很近很近。 骗子一般不太敢接电话和视频要求。如果你尝试和对方进行视频或者语音的话,对方大概率会拒绝。当然骗子会语音,视频要求接受的可能性不大。当然这个并不是非常保险,回到最后的底线就是不转账就行。   https://www.usreio.com/t/topic/224

2022年08月03日 0Comments 484Browse 0Like Read more
Computer Science

Java Optional 初始为空

如果你想对 Optional 进行初始化的话,你可能会考虑使用下面的代码: Optional<QualificationStateLabelInfo> stateSpecificLabel = null; 上面的代码编译和运行都没有问题。 如何初始化 正确的初始化代码是: Optional<QualificationStateLabelInfo> stateSpecificLabel = Optional.empty(); 上面将会把你定义的 Optional 初始化为空。     但是我们会避免使用 null。 https://www.ossez.com/t/java-optional/13975

2022年08月03日 0Comments 415Browse 0Like Read more
Computer Science

Java 8 开始新增的 Optional 类 - Optional 对象中的返回

使用 get() 来返回一个值 在对 Optional 对象完成一些检查和校验后,我们可以使用 get() 方法来返回对象中的值。 // returning Value With get() @Test public void givenOptional_whenGetsValue_thenCorrect() { Optional<String> opt = Optional.of("HoneyMoose"); String name = opt.get(); assertEquals("HoneyMoose", name); } 与 orElse() 或者 orElseGet() 方法不一样的地方是 get() 只会在 Optional 包装的对象不为 null 的时候返回值,否则这个方法将会抛出一个没有这个元素(no such element exception)的异常 。 @Test(expected = NoSuchElementException.class) public void givenOptionalWithNull_whenGetThrowsException_thenCorrect() { Optional<String> opt = Optional.ofNullable(null); String name = opt.get(); } 上面的方法显示了如何使用 get() 方法来获得 Optional 中元素的典型操作。 我们使用 Optional 的主要原因就是为了避免在程序中出现 Null 对象异常的这种情况,但是 get() 方法的这种操作还是会给你带来空对象异常的。 因此需要注意下这种代码编写方式,也有可能在 JDK 的后续版本中,这个 get() 方法有可能被取消掉,但是目前还不会。   正是因为这种情况,get() 这个方法也有可能出现空对象异常,在编码的时候还是需要注意下的。 使用 filter() 来进行条件返回 我们可以使用 filter() 方法在输出之前进行测试,然后过滤出满足我们条件的返回对象。 这个方法将会使用 Java 提供的谓语(predicate )作为参数来返回 Optional 对象。 如果通过了 Java 提供的谓语(predicate )测试的话,Optional 对象将会被原样返回。 如果,测试的 谓语(predicate )为 False 的话,那么一个空的 Optional 对象将会被返回。 @Test public void whenOptionalFilterWorks_thenCorrect() { Integer year = 2016; Optional<Integer> yearOptional = Optional.of(year); boolean is2016 = yearOptional.filter(y -> y == 2016).isPresent(); assertTrue(is2016); boolean is2017 = yearOptional.filter(y -> y == 2017).isPresent(); assertFalse(is2017); } filter() 方法通常用来处理你不需要的返回,或者处理满足你条件的返回。 例如在对用户电子邮件进行检查,或者用户密码进行检查的时候,我们可以设置这样一个 filter() 过滤器,当不满足我们设置条件的时候,我们让程序返回一个空的对象,以此来设置条件。 让我们看另外一个使用场景,我们希望购买一个调制解调器(modem),但是我们只关注的是价格,我们对信号灯并不敏感 我们希望对调制解调器在满足价格区间的时候获得一个通知: public class Modem { private Double price; public Modem(Double price) { this.price = price; } // standard getters and setters } 让我们让这个对象通过一些代码来检查这个对象是不是满足我们设定的价格区间. 下面的代码是我们不使用 Optional 的时候的代码。 从上面的代码来看,我们需要进行 Null 检查,然后获得价格,然后判断价格,更要命的更极端的情况价格也有可能为 null。 public boolean priceIsInRange1(Modem modem) { boolean isInRange = false; if (modem != null && modem.getPrice() != null && (modem.getPrice() >= 10 && modem.getPrice() <= 15)) { isInRange = true; } return isInRange; } 为了满足 Null 检查的所有条件,我们需要不停的 if 进行判断。我们需要通过这些 if 条件检查来确定是否满足我们的条件,并且这个代码看起来有点郁闷,但是实际上也确实就是这样写的。 @Test public void whenFiltersWithoutOptional_thenCorrect() { assertTrue(priceIsInRange1(new Modem(10.0))); assertFalse(priceIsInRange1(new Modem(9.9))); assertFalse(priceIsInRange1(new Modem(null))); assertFalse(priceIsInRange1(new Modem(15.5))); assertFalse(priceIsInRange1(null)); } 同时,你也有可能忘记某一个检查,比如说价格为 NULL 的时候怎么办。 这个检查在编译的时候是不会提示你的,只有程序真正上线运行了,出现了异常了,你才知道,我又忘记检查空了。 现在我们看看 Optional 中的 filter() 是怎么做的。 public boolean priceIsInRange2(Modem modem2) { return Optional.ofNullable(modem2).map(Modem::getPrice).filter(p -> p >= 10).filter(p -> p <= 15).isPresent(); } 你的程序精简到只需要一行就可以了。 map 这个方法只是简单的从对象中获得值,后面的过滤器才是对获得值进过滤的。 需要注意的是,使用 filter() 不会对输入的参数进行修改。 在我们的用例中,我们非常容易的就从我们的 Model 对象中获得了价格的属性。至于 map() 的使用我们在后面的内容中进行介绍。 针对上面的代码,首先如果对象出现 null 的时候是不会对你程序有任何影响的,还是能一直跑下去的。 其次就是逻辑非常简单,整个逻辑就是对价格进行判断,至于其他的 null 判断都是由 Optional 完成的。 @Test public void whenFiltersWithOptional_thenCorrect() { assertTrue(priceIsInRange2(new Modem(10.0))); assertFalse(priceIsInRange2(new Modem(9.9))); assertFalse(priceIsInRange2(new Modem(null))); assertFalse(priceIsInRange2(new Modem(15.5))); assertFalse(priceIsInRange2(null)); } 最开始的 If 代码也是可以完成价格的判断的,但是这个方法有着自身的缺陷,因此我们使用了…

2022年08月03日 0Comments 534Browse 0Like Read more
1…108109110111112…304
Archives
  • June 2026
  • May 2026
  • April 2026
  • March 2026
  • February 2026
  • January 2026
  • December 2025
  • November 2025
  • October 2025
  • September 2025
  • August 2025
  • July 2025
  • June 2025
  • May 2025
  • April 2025
  • March 2025
  • February 2025
  • January 2025
  • December 2024
  • November 2024
  • October 2024
  • September 2024
  • August 2024
  • July 2024
  • June 2024
  • May 2024
  • April 2024
  • March 2024
  • February 2024
  • January 2024
  • December 2023
  • November 2023
  • October 2023
  • September 2023
  • August 2023
  • July 2023
  • June 2023
  • May 2023
  • April 2023
  • December 2022
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • May 2022
  • April 2022
  • March 2022
  • February 2022
  • January 2022
  • December 2021
  • November 2021
  • October 2021
  • September 2021
  • August 2021
  • July 2021
  • June 2021
  • May 2021
  • April 2021
  • March 2021
  • February 2021
  • January 2021
  • December 2020
  • November 2020
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020
  • May 2020
  • April 2020
  • March 2020
  • February 2020
  • January 2020
  • December 2019
  • November 2019
  • October 2019
  • September 2019
  • August 2019
  • July 2019
  • June 2019
  • May 2019
  • April 2019
  • March 2019
  • February 2019
  • January 2019
  • December 2018
  • November 2018
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • April 2018
  • March 2018
Categories
  • Computer Science (2,367)
    • Confluence (663)
    • Gradle (12)
  • U.S. (522)
  • 文化旅游 (146)

COPYRIGHT © 2020 CWIKIUS. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

湘ICP备2020018253号-1