assignment java_Java中的快捷方式“or-assignment”(| =)运算符

我在爪哇有一个很长的比较,我想知道他们中的一个或多个是否是真的。比较字符串很长,很难读取,所以为了可读性,我将其拆分,然后自动使用快捷运算符|=,而不是negativeValue = negativeValue || boolean。

boolean negativeValue = false;

negativeValue |= (defaultStock < 0);

negativeValue |= (defaultWholesale < 0);

negativeValue |= (defaultRetail < 0);

negativeValue |= (defaultDelivery < 0);

如果任何一个默认值为负数,我希望negativeValue为真。这是有效的吗?它会像我期望的那样吗?我在Sun的网站或StackOverflow上看不到它的相关内容,但Eclipse似乎不存在问题,代码可以编译和运行。

同样,如果我想执行几个逻辑交叉,我可以使用&=而不是&&吗?

你为什么不试试呢?

这是一般的布尔逻辑,而不是Java。所以你可以在其他地方查。你为什么不试试呢?

@戴卡姆:不,这里有具体的行为。Java可以选择进行"短路",这样,如果LHS已经是真的,它就不会评估RHS。

嗯,哎呀,我错过了那个。但是在这个例子中,RHS没有副作用,所以行为在这里除了性能之外,不起作用,是吗?

@jon skeet:短路适用于不存在的||=运算符,但|=是按位或运算符的组合形式。

@大卫:我不是想说应该发生。我只是说这是一个语言行为问题,而不仅仅是布尔逻辑。

@乔恩·斯基特:当然,但是使|=短路会与其他复合赋值运算符不一致,因为a |= b;与a = a | b;不同,通常会对a进行两次评估(如果重要的话)。在我看来,大语言行为决定并不是由||=决定的,所以我没有理解你的观点。

David Thornley:我的第一个评论是驳斥Dykam声称这个问题不属于Java的说法。它是。我完全同意这里的Java设计决定,但这并没有使语言变得更具体。

|=是用于布尔逻辑运算符|(jls 15.22.2)的复合赋值运算符(jls 15.26.2);不要与条件运算符或||混淆(jls 15.24)。还有对应于布尔逻辑&和^的复合赋值版本的&=和^=。

换言之,对于boolean b1, b2,这两个值是相等的:

b1 |= b2;

b1 = b1 | b2;

逻辑运算符(&和|与条件运算符(&&和||相比)的区别在于前者不"短路";后者确实短路。即:

&和|总是评估两个操作数

&&和||有条件地计算右操作数;只有当右操作数的值可能影响二进制运算的结果时,才计算右操作数。这意味着在以下情况下不计算右操作数:

&&的左操作数计算为false。

(因为无论右操作数的计算结果如何,整个表达式都是false)

||的左操作数计算为true。

(因为无论右操作数的计算结果如何,整个表达式都是true)

所以回到你最初的问题,是的,这个构造是有效的,虽然|=并不是=和||的一个等价快捷方式,但它确实计算出你想要的。由于您使用的|=运算符的右侧是一个简单的整数比较运算,因此|不短路的事实是微不足道的。

有些情况下,需要短路,甚至需要短路,但您的场景不是其中之一。

不幸的是,与其他语言不同,Java没有EDCOX1 29和EDCOX1 30。这是在Java为什么没有条件和条件或操作符的复合赋值版本的问题中讨论的?(&amp;&amp;=,=)。

+1,非常彻底。如果编译器能够确定rhs没有副作用,那么它很可能转换成短路运算符,这似乎是合理的。有什么线索吗?

我读到,当rhs是微不足道的,sc是不必要的,"智能"sc运营商实际上有点慢。如果是真的,那么更有趣的是想知道在某些情况下,某些编译器是否可以将sc转换为nsc。

@PolygeneLubricants短路运算符涉及到引擎盖下某种类型的分支,因此,如果没有分支预测友好模式,则与运算符和/或使用中的体系结构一起使用的真值没有良好的/任何分支预测(并且假定编译器和/或虚拟机不进行任何相关的优化)当然,SC操作人员会引入一些与非短路相比的慢度。找到编译器的最佳方法是使用sc和nsc编译一个程序,然后比较字节码,看它是否不同。

另外,不要与也是|的按位或运算符混淆。

它不是一个"捷径"(或短路)操作员,就像和&amp;&amp;那样(如果他们已经知道基于lhs的结果,他们不会评估rhs),但在工作方面它会做你想要做的。

作为区别的一个例子,如果text为空,则此代码将很好:

boolean nullOrEmpty = text == null || text.equals("")

然而,这不会:

boolean nullOrEmpty = false;

nullOrEmpty |= text == null;

nullOrEmpty |= text.equals(""); // Throws exception if text is null

(很明显,你可以为这个特定的案例做"".equals(text)--我只是想证明这个原则。)

你只要一句话。它在多行上表示,读起来几乎与您的示例代码完全相同,只是命令性较低:

boolean negativeValue

= defaultStock < 0

| defaultWholesale < 0

| defaultRetail < 0

| defaultDelivery < 0;

对于最简单的表达式,使用|可能比||更快,因为即使它避免进行比较,它也意味着隐式使用分支,而且可能比使用分支贵很多倍。

我的确是从一个开始,但正如最初的问题所述,我觉得"这串比较很长,很难阅读,所以为了可读性,我把它拆开了"。除此之外,在本例中,我更感兴趣的是学习=的行为,而不是让这段特定的代码工作。

这是一篇老文章,但为了给初学者提供一个不同的视角,我想举个例子。

我认为对于类似的复合操作符最常见的用例是+=。我相信我们都写了这样的东西:

int a = 10;   // a = 10

a += 5;   // a = 15

这有什么意义?重点是避免样板文件和消除重复的代码。

因此,下一行的操作完全相同,避免在同一行中键入两次变量b1。

b1 |= b2;

在操作和运算符名称中很难发现错误,尤其是在名称较长的情况下。longNameOfAccumulatorAVariable += 5;对longNameOfAccumulatorAVariable = longNameOfAccumulatorVVariable + 5;的比较

如果它是关于可读性的,我已经有了将测试数据与测试逻辑分离的概念。代码示例:

// declare data

DataType [] dataToTest = new DataType[] {

defaultStock,

defaultWholesale,

defaultRetail,

defaultDelivery

}

// define logic

boolean checkIfAnyNegative(DataType [] data) {

boolean negativeValue = false;

int i = 0;

while (!negativeValue && i < data.length) {

negativeValue = data[i++] < 0;

}

return negativeValue;

}

这段代码看起来更冗长,更容易解释。甚至可以在方法调用中创建数组,如下所示:

checkIfAnyNegative(new DataType[] {

defaultStock,

defaultWholesale,

defaultRetail,

defaultDelivery

});

它比"比较字符串"更可读,而且还具有短路的性能优势(以数组分配和方法调用为代价)。

编辑:使用varargs参数可以简单地实现更高的可读性:

方法签名为:

boolean checkIfAnyNegative(DataType ... data)

电话看起来是这样的:

checkIfAnyNegative( defaultStock, defaultWholesale, defaultRetail, defaultDelivery );

数组分配和方法调用对于短路来说是一个相当大的成本,除非在比较中有一些昂贵的操作(但问题中的示例很便宜)。尽管如此,大多数时候代码的可维护性将超过性能考虑。如果我在一堆不同的地方进行不同的比较,或者比较4个以上的值,我可能会使用类似的方法,但是对于一个例子来说,这对于我的口味来说有点冗长。

@戴维森,我同意。然而,请记住,大多数现代计算器将在不到几毫秒的时间内吞下这种开销。就我个人而言,在性能问题看来是合理的之前,我不会关心开销。另外,代码冗长也是一个优势,特别是当jautodoc没有提供或生成javadoc时。

尽管对于您的问题来说,它可能是多余的,但guava库与Predicates有一些很好的语法,并对or/and Predicates进行短路评估。

本质上,比较被转换成对象,打包成一个集合,然后迭代。对于或谓词,第一个真正命中从迭代返回,反之亦然。

||逻辑布尔或按位或

|=按位包含或与赋值运算符

=不短路的原因是它执行的是位或非逻辑或。这就是说:

C |= 2 is same as C = C | 2

Java操作员教程

没有位或布尔值!运算符EDCOX1〔1〕是整数位的,但也是逻辑的,或参见Java语言规范1522.2。

您是正确的,因为对于单个位(布尔值),位和逻辑或是等价的。实际上,结果是一样的。

List params = Arrays.asList (defaultStock, defaultWholesale,

defaultRetail, defaultDelivery);

int minParam = Collections.min (params);

negativeValue = minParam < 0;

我想我更喜欢negativeValue = defaultStock < 0 || defaultWholesale < 0等。除了这里所进行的所有装箱和包装的效率低下之外,我发现理解您的代码真正意味着什么几乎没有那么容易。

他有4个以上的参数,所有参数的标准都是一样的,所以我喜欢我的解决方案,但是为了可读性,我将它分成几行(即创建列表、查找minvalue、将minvalue与0进行比较)。

对于大量的比较来说,这确实很有用。在这种情况下,我认为降低清晰度不值得节省打字等费用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的Java程序,它可以将两种货币之间的汇率进行转换。在程序,我们使用了一个HashMap来存储货币之间的汇率。您可以根据需要对其进行修改。 ```java import java.util.HashMap; import java.util.Scanner; public class CurrencyConverter { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); HashMap<String, Double> exchangeRates = new HashMap<>(); exchangeRates.put("USD", 1.0); exchangeRates.put("EUR", 0.85); exchangeRates.put("GBP", 0.75); exchangeRates.put("JPY", 111.28); exchangeRates.put("CNY", 6.47); System.out.print("Enter the amount: "); double amount = scanner.nextDouble(); System.out.print("Enter the currency to convert from: "); String fromCurrency = scanner.next().toUpperCase(); System.out.print("Enter the currency to convert to: "); String toCurrency = scanner.next().toUpperCase(); double fromRate = exchangeRates.get(fromCurrency); double toRate = exchangeRates.get(toCurrency); double result = amount * (toRate / fromRate); System.out.println(amount + " " + fromCurrency + " is equivalent to " + result + " " + toCurrency + "."); } } ``` 运行程序后,您可以输入要转换的金额、要转换的货币和要转换成的货币,程序会计算并输出转换后的金额。例如,如果您要将100美元转换为欧元,您可以输入以下内容: ``` Enter the amount: 100 Enter the currency to convert from: USD Enter the currency to convert to: EUR ``` 程序将输出: ``` 100.0 USD is equivalent to 85.0 EUR. ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值