string 如何在 Scala 中简洁地用默认字符串替换空字符串(或 null)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18417321/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to substitute an empty string (or null) with a default string concisely in Scala
提问by trustin
I have a method that returns a String. I want to substitute it with a default value such as "<empty>"
if it returns an empty string or null
. Let's assume its name is getSomeString
, it is an expensive operation so I can call it only once, and I can't change its return type to Option[String]
. For now, I'm doing the following:
我有一个返回字符串的方法。我想用默认值替换它,例如"<empty>"
如果它返回一个空字符串或null
. 让我们假设它的名字是getSomeString
,这是一个昂贵的操作,所以我只能调用它一次,而且我不能将它的返回类型更改为Option[String]
。现在,我正在执行以下操作:
val myStr = {
val s = getSomeString
if (s == null || s.isEmpty) "<empty>" else s
}
Is there a simpler way to achieve the same thing?
有没有更简单的方法来实现同样的目标?
采纳答案by som-snytt
Given an expensive function:
给定一个昂贵的函数:
scala> def s(i: Int): String = i match { case 0=>null case 1=>"" case 2=>"hi" }
s: (i: Int)String
I think this is easy to read and free of overhead, cf this in the wild:
我认为这是容易阅读和自由开销,CF在野外此:
scala> def q(i: Int) = s(i) match { case ""|null => "<empty>" case x => x }
q: (i: Int)String
scala> q(0)
res3: String = <empty>
scala> q(1)
res4: String = <empty>
scala> q(2)
res5: String = hi
To my eyes, this is not as expressive, even with minimalist punctuation:
在我看来,即使使用极简标点符号,这也没有那么富有表现力:
scala> Option(s(0)) filterNot (_.isEmpty) getOrElse "<empty>"
res6: String = <empty>
Moreover, contrast the cost in anonfun
classes for the closures and additional method invocations:
此外,对比anonfun
闭包和额外方法调用的类成本:
scala> :javap -
Size 1161 bytes
MD5 checksum 765f5f67b0c574252b059c8adfab1cf0
Compiled from "<console>"
[...]
9: getstatic #26 // Field scala/Option$.MODULE$:Lscala/Option$;
12: getstatic #31 // Field .MODULE$:L;
15: iconst_0
16: invokevirtual #35 // Method .s:(I)Ljava/lang/String;
19: invokevirtual #39 // Method scala/Option$.apply:(Ljava/lang/Object;)Lscala/Option;
22: new #41 // class $anonfun
25: dup
26: invokespecial #42 // Method $anonfun."<init>":()V
29: invokevirtual #48 // Method scala/Option.filterNot:(Lscala/Function1;)Lscala/Option;
32: new #50 // class $anonfun
35: dup
36: invokespecial #51 // Method $anonfun."<init>":()V
39: invokevirtual #55 // Method scala/Option.getOrElse:(Lscala/Function0;)Ljava/lang/Object;
42: checkcast #57 // class java/lang/String
45: putfield #17 // Field res6:Ljava/lang/String;
The pattern match is generally just an if-else, smaller and faster (even considering that it doesn't optimise s == ""
to s.isEmpty
):
模式匹配通常只是一个 if-else,更小更快(即使考虑到它没有优化s == ""
为s.isEmpty
):
scala> :javap -r #q
public java.lang.String q(int);
flags: ACC_PUBLIC
Code:
stack=2, locals=5, args_size=2
0: getstatic #19 // Field $line3/$read$$iw$$iw$.MODULE$:L$line3/$read$$iw$$iw$;
3: iload_1
4: invokevirtual #22 // Method $line3/$read$$iw$$iw$.s:(I)Ljava/lang/String;
7: astore_3
8: ldc #24 // String
10: aload_3
11: invokevirtual #28 // Method java/lang/Object.equals:(Ljava/lang/Object;)Z
14: ifeq 22
17: iconst_1
18: istore_2
19: goto 33
22: aload_3
23: ifnonnull 31
26: iconst_1
27: istore_2
28: goto 33
31: iconst_0
32: istore_2
33: iload_2
34: ifeq 44
37: ldc #30 // String <empty>
39: astore 4
41: goto 47
44: aload_3
45: astore 4
47: aload 4
49: areturn
But inspired by the other answer, even if I would never take this code home to meet my parents (because it incorrectly converts the value "null"
if the expensive function returns it -- though maybe it's a feature to do that), here is a regex:
但是受到另一个答案的启发,即使我永远不会把这段代码带回家见我的父母(因为"null"
如果昂贵的函数返回它,它会错误地转换该值——尽管它可能是这样做的一个功能),这里是一个正则表达式:
scala> def p(i: Int) = "" + s(i) replaceAll ("^null$|^$", "<empty>")
p: (i: Int)String
The "" + s(i)
is a shorthand for String.valueOf
, which of course produces the String "null"
for a null reference value. I appreciate SO's ability not only to generate quick answers to questions, but to encourage some out-of-the-box thinking.
The"" + s(i)
是 的简写String.valueOf
,它当然会"null"
为空引用值生成 String 。我很欣赏 SO 不仅能够快速回答问题,而且还能鼓励一些开箱即用的思维。
回答by Brian Hsu
val myStr = Option(getSomeString).filterNot(_.isEmpty).getOrElse("<empty>")
Updated
更新
I posted this code because I think the intent in this code is clear than if/else or pattern matching version, but I didn't consider the performance issue.
我发布此代码是因为我认为此代码的意图比 if/else 或模式匹配版本更清楚,但我没有考虑性能问题。
As the others in comments mentioned, this code is much slower than simple if / else or pattern matching(this line will create a lot new objects which is an expensive operation), so please do not use this code when performance is an issue.
正如评论中的其他人所提到的,此代码比简单的 if / else 或模式匹配慢得多(此行将创建很多新对象,这是一项昂贵的操作),因此请不要在性能有问题时使用此代码。
回答by Beryllium
You could add a method to String
using an implicit value class
您可以添加一个方法来String
使用隐式值类
object ImplicitClassContainer {
implicit class RichString(val s: String) extends AnyVal {
def getOrDefault(defaultValue: String): String = {
s match {
case null | "" => defaultValue
case x => x
}
}
}
to be used like this
像这样使用
import ImplicitClassContainer._
println("hi".getOrDefault("<empty1>"))
println("".getOrDefault("<empty2>"))
val s: String = null
println(s.getOrDefault("<empty3>"))
so even the method call on null
is handled gracefully (Scala 2.10.1).
所以即使是方法调用也null
被优雅地处理(Scala 2.10.1)。
回答by Micha? Kosmulski
You could replace null with empty string in first step using Option
and then substitute with default text if result is empty (whether because it was empty originally or because it was null):
您可以在第一步中使用空字符串替换 null ,Option
然后如果结果为空(无论是因为它最初为空还是因为它为空),则用默认文本替换:
Option(getSomeString).getOrElse("").replaceAll("^$","<empty>")
回答by Roman Kazanovskyi
If you don't need changes:
如果您不需要更改:
Option(getSomeString).fold("<empty>")(s => s)
If you need to modify if for nonEmpty result. Simple example:
如果需要修改 if for nonEmpty 结果。简单的例子:
Option(getSomeString).fold("<empty>")(str => s"xxxxxxxx$str")
回答by dev-null
val myStr = getSomeString match { case ""|null => "<empty>" case s => s }