A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© -___Is、_C 中级黑马   /  2013-9-23 15:22  /  2003 人查看  /  9 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 -___Is、_C 于 2013-9-24 07:56 编辑

刚刚看到一则判断空字符串有3中方法的日志。那想3种方法究竟那一种方法性能最高呢?求解??3种方法分别是:string a="";
1.if(a=="")
2.if(a==String.Empty)
3.if(a.Length==0)


评分

参与人数 1技术分 +1 收起 理由
haxyek + 1

查看全部评分

9 个回复

倒序浏览
通常我们判断空字符串,在c#会使用 if (x = "")的方法,首先要明确在c#中空字符串可以是"",String.Empty和null这三种,三者的定义如下,

1."",是分配一个长度为空的内存空间;
2.String.Empty,不分配内存空间,一般用string.Empty来定义。(另有一说是分配有内存空间的)
3.null,没有分配内存空间;

一般来说1和2基本上是可以互换使用,例如:

String temp="";
String temp1=string.Empty;

在使用IF语句作判断的时候,
if (temp == string.Empty)
{
}

if (temp1 == "")
{
}
if的语句都成立的。


判断空字符串可以用以下三种方法,按性能从高到低的顺序为:

str.Length==0 、str==String.Empty 、str == ""

那现在需要区分string.Empty与null在判断的时候是否一样。

如果string str=null后使用str.length == 0 将会报错,对于null通常使用 if (str == null) 这样的方法来作判断。

SO,str.Length==0 、str==String.Empty 、str == ""这三种方法,对于null的空字符串,似乎是无效的。

c#提供了有一个函数,string.IsNullOrEmpty(),如果 string为空或空字符串 ("")、null等,则为 true;否则为 false。

该函数可以同时检测,"",string.Empty,null等情况,

IsNullOrEmpty 是一种简便方法,它使您能够同时测试 String 是否为空或其值是否为 Empty。 它与下列代码等效:

result = s Is Nothing OrElse s = String.Empty
1、result = s == null || s == String.Empty;  
2、result = s == nullptr || s == String::Empty;

评分

参与人数 1技术分 +1 收起 理由
haxyek + 1

查看全部评分

回复 使用道具 举报
我觉得应该是第二种吧,还有一种判断是否为空的方法:
String.IsNullOrEmpty(s) == true
回复 使用道具 举报
再.NET中。我还是觉得你想的太多了。我们知道。net有GC管理机制。你在这里 即便是用第一种 a=“”这种来判空。所分配的空间会被GC堆回收的。而且,我个人认为 a=""这种方法更简单和通俗。
回复 使用道具 举报
1. 三种常用的字符串判空串方法:
Length法:bool isEmpty = (str.Length == 0);
Empty法:bool isEmpty = (str == String.Empty);
General法:bool isEmpty = (str == "");
2. 深入内部机制:
要探讨这三种方法的内部机制,我们得首先看看.NET是怎样实现的,也就是要看看.NET的源代码!然而,我们哪里找这些源代码呢?我们同样有三种方法:
Rotor法:一个不错的选择就是微软的Rotor,这是微软的一个源代码共享项目。
Mono法:另一个不错的选择当然就是真正的开源项目Mono啦!
Reflector法:最后一个选择就是使用反编译器,不过这种重组的代码不一定就是原貌,只不过是一种“近似值”,你可以考虑使用Reflector这个反编译器[1]。
这里我采用Reflector法,我们先来看看一下源代码[2](片段):
复制代码 代码如下:
public sealed class String : IComparable, ICloneable, IConvertible, IEnumerable, IComparable<string>
...{
    static String()
    ...{
        string.Empty = "";
        // Code here
    }
    // Code here
    public static readonly string Empty;
    public static bool operator ==(string a, string b)
    ...{
        return string.Equals(a, b);
    }
    public static bool Equals(string a, string b)
    ...{
        if (a == b)
        ...{
            return true;
        }
        if ((a != null) && (b != null))
        ...{
            return string.EqualsHelper(a, b);
        }
        return false;
    }
    private static unsafe bool EqualsHelper(string ao, string bo)
    ...{
        // Code here
        int num1 = ao.Length;
        if (num1 != bo.Length)
        ...{
            return false;
        }
        // Code here
    }
    private extern int InternalLength();
    public int Length
    ...{
        get
        ...{
            return this.InternalLength();
        }
    }
    // Code here
}

Rotor里面String类的代码与此没什么不同,只是没有EqualsHelper方法,代之以如下的声明:
public extern bool Equals(String value);
进一步分析:
首先是Empty法,由于String.Empty是一个静态只读域,只会被创建一次(在静态构造函数中)。但当我们使用Empty法进行判空时,.NET还会依次展开调用以下的方法,而后两个方法内部还会进行对象引用判等!
public static bool operator ==(string a, string b);
public static bool Equals(string a, string b);
private static unsafe bool EqualsHelper(string ao, string bo);
若使用General法判等的话,情况就“更胜一筹”了!因为.NET除了要依次展开调用上面三个方法之外,还得首先创建一个临时的空字符串实例,如果你要进行大量的比较,这恐怕是想一想就很吓人了!
而对于Length法,我们就可以绕过上面这些繁琐的步骤,直接进行整数(字符串长度)判等,我们知道,大多数情况下,整数判等都要来得快(我实在想不出比它更快的了,在32位系统上,System.Int32运算最快了)!
另外,我们还可以看到,在EqualsHelper方法里面.NET会先使用Length法来进行判等!可惜的是我无法获得InternalLength方法的代码。但我在Mono的源代码里面看到更简明的实现:
复制代码 代码如下:
class String
...{
    private int length;
    public int Length
    ...{
        get
        ...{
            return length;
        }
    }
    // .
}

然而使用Length法进行字符串判空串时,有一点要注意的,就是你必须先判断该字符串实例是否为空引用,否则将会抛出NullReferenceException异常!于是,我们有了一个经过改进的Length法:
复制代码 代码如下:
void Foo(string bar)
...{
    if ((bar != null) && (bar.Length == 0))
        //
}

3. 最后总结:
从上面的分析我们可以看到,使用Length法来进行字符串判空串是有着很大的性能优势的,尤其在进行大量字符串判空时!当然首先得判断字符串实例是否为空引用!

评分

参与人数 1技术分 +1 收起 理由
haxyek + 1

查看全部评分

回复 使用道具 举报
(1)NULL
null 关键字是表示不引用任何对象的空引用的文字值。null 是引用类型变量的默认值。那么也只有引用型的变量可以为NULL,如果int i=null,的话,是不可以的,因为Int是值类型的。


(2)""和String.Empty
   这两个都是表示空字符串。只不过""理论上重新开辟内存空间,而String.Empty指向一处。不过优化器会优化的!

   string.Empty不分配存储空间, ""分配一个长度为空的存储空间,所以一般用string.Empty,为了以后跨平台,还是用string.empty。在C# 中,大多数情况下 "" 和 string.Empty 可以互换使用。比如:

string s = "";

string s2 = string.Empty;


if (s == string.Empty) {

//

}if语句成立


判定为空字符串的几种写法,按照性能从高到低的顺序是:


s.Length == 0 优于 s == string.Empty 优于 s == ""



注意:


   1.string str1="" 和 string str2=null 的区别。str1是一个空字符串,空字符串是一个特殊的字符串,只不过这个字符串的值为空,在内存中是有准确的指向的,string str2=null,这样定义后,只是定义了一个string 类的引用,str2并没有指向任何地方,在使用前如果不实例化的话,都将报错。


2.在net 2.0中可用String.IsNullOrEmpty(param)检测是否为null或为空值。


当Request.QueryString的标识不存在时返回的是NULL,可以在空串上调用string类的所有方法,但null不可以,不可以在null上调用方法。


(3)DBNULL

      DBNull在DotNet是单独的一个类型, 该类用于指示不存在某个已知值(通常在数据库应用程序中)。该类只能存在唯一的实例,DBNULL.Value, DBNull唯一作用是可以表示数据库中的字符串,数字,或日期,为什么可以表示原因是DotNet储存这些数据的类(DataRow等)都是以 object 的形式来储存数据的。对于 DataRow , 它的 row[column] 返回的值永远不为 null , 要么就是具体的为column 的类型的值 。 要么就是 DBNull 。 所以 row[column].ToString() 这个写法永远不会在ToString那里发生NullReferenceException。DBNull 实现了 IConvertible 。 但是,除了 ToString 是正常的外,其他的ToXXX都会抛出不能转换的错误。
      

评分

参与人数 1技术分 +1 收起 理由
haxyek + 1

查看全部评分

回复 使用道具 举报
茹化肖 发表于 2013-9-23 16:36
再.NET中。我还是觉得你想的太多了。我们知道。net有GC管理机制。你在这里 即便是用第一种 a=“”这种来判 ...

 首先,GC并不是能释放所有的资源。它不能自动释放非托管资源。

 第二,GC并不是实时性的,这将会造成系统性能上的瓶颈和不确定性。

所以你就不要指望gc机制是万能的了,如果能有更好具效率的方法判断的话,就用吧,这样会使程序更具效率,更稳定。作为一个程序员我们考虑的不应该只是让程序能够运行起来,而是要让程序性能更好,更稳定所以要优化自己的程序啦。{:soso_e100:}


回复 使用道具 举报
七里香 发表于 2013-9-24 12:11
 首先,GC并不是能释放所有的资源。它不能自动释放非托管资源。 第二,GC并不是实时性的, ...

知识有限,谢谢指教。我会再学习的。{:soso_e100:}
回复 使用道具 举报
3.if(a.Length==0)
效率最高!
回复 使用道具 举报
茹化肖 发表于 2013-9-23 16:36
再.NET中。我还是觉得你想的太多了。我们知道。net有GC管理机制。你在这里 即便是用第一种 a=“”这种来判 ...

此言差矣!   GC管理机制那是后话!   现在呀考虑的是时间复杂度 空间复杂度。   装箱 拆箱的操作
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马