为什么这个变量在初始化为空字符串时设置为空字符串?

时间:2022-09-11 19:47:56

I have taken the following code snippet from the 5th snippet on this developer guide on Content Providers.

我从内容提供商的开发者指南的第5个片段中获取了以下代码段。

The confusion is that in the first statement String[] mSelectionArgs = {""};, mSelectionArgs[0] IS set to "".

令人困惑的是,在第一个语句String [] mSelectionArgs = {“”} ;, mSelectionArgs [0] IS设置为“”。

Then later if the mSearchString is empty (TextUtils.isEmpty(mSearchString)), then again mSelectionArgs[0] is assigned "".

然后如果mSearchString为空(TextUtils.isEmpty(mSearchString)),则再次为mSelectionArgs [0]分配“”。

So the question is that why are they setting it to an empty string when it is already initialized to an empty string?

所以问题是,当它已经初始化为空字符串时,为什么将它设置为空字符串?

/*
 * This defines a one-element String array to contain the selection argument.
 */
String[] mSelectionArgs = {""};

// Gets a word from the UI
mSearchString = mSearchWord.getText().toString();

// Remember to insert code here to check for invalid or malicious input.

// If the word is the empty string, gets everything
if (TextUtils.isEmpty(mSearchString)) {
    // Setting the selection clause to null will return all words
    mSelectionClause = null;
    mSelectionArgs[0] = "";

} else {
    // Constructs a selection clause that matches the word that the user entered.
    mSelectionClause = UserDictionary.Words.WORD + " = ?";

    // Moves the user's input string to the selection arguments.
    mSelectionArgs[0] = mSearchString;

}
...

2 个解决方案

#1


2  

Except for additional clarity and code readability, as noted in another answer, this coding style makes for a less error prone code which is easier to maintain.

除了额外的清晰度和代码可读性之外,如另一个答案中所述,这种编码风格使得更容易出错的代码更容易维护。

This way, if the initial value of mSelectionArgs is changed, or new code added which overrides this value before the execution of the if-else block, the code of this block will still execute correctly. Without this "rudimentary" assignment, a change as described above could lead to a bug which would be very difficult to trace.

这样,如果更改了mSelectionArgs的初始值,或者添加了在执行if-else块之前覆盖此值的新代码,则此块的代码仍将正确执行。如果没有这种“基本”的分配,如上所述的改变可能会导致一个很难追查的错误。

As a side note:

作为旁注:

This specific code snippet is not that good (yes, I know it is from Android Developers site...) - if you pass null as selection argument to query(), then it is better to also pass null as selectionArgs argument. I'd modify this sample to something like this (setting both selection and selectionArgs to null):

这个特定的代码片段并不是那么好(是的,我知道它来自Android Developers网站......) - 如果你将null作为选择参数传递给query(),那么最好还将null作为selectionArgs参数传递。我将此示例修改为类似的内容(将selection和selectionArgs都设置为null):

// Gets a word from the UI

mSearchString = mSearchWord.getText().toString();

// Remember to insert code here to check for invalid or malicious input.

String[] mSelectionArgs = null;

// If the word is the empty string, gets everything
if (TextUtils.isEmpty(mSearchString)) {
    // Setting the selection clause to null will return all words
    mSelectionClause = null;
    mSelectionArgs = null;

} else {
    // Constructs a selection clause that matches the word that the user entered.
    mSelectionClause = UserDictionary.Words.WORD + " = ?";

    // Moves the user's input string to the selection arguments.
    mSelectionArgs = new String[] {mSearchString};

}

Edit: why the above code snippet is better than the original one?

编辑:为什么上面的代码片段比原来的更好?

It is not an error to pass null as selection and non-null as selectionArgs. This array will be passed to the specific ContentProvider you're addressing, and shouldn't be used at all since selection does not contain any ? placeholders. Any ContentProvider violating this assumption is buggy. Although not an error, it just looks weird - why do you pass an object that should be ignored anyway? This also has performance cost (which is higher if ContentProvider runs in different process), which is proportional to the size of the object being passed.

将null作为选择传递并将非null作为selectionArgs传递并不是错误。此数组将传递给您正在寻址的特定ContentProvider,并且根本不应该使用,因为选择不包含任何内容?占位符。违反此假设的任何ContentProvider都是错误的。虽然不是错误,但它看起来很奇怪 - 为什么你传递一个应该被忽略的对象?这也有性能成本(如果ContentProvider在不同的进程中运行,则会更高),这与传递的对象的大小成比例。

Edit 2: why the above code snippet is MUCH better than the original one? Turns out that what I said above might be misleading. I found it out the hard way:

编辑2:为什么上面的代码片段比原始代码片段好多了?事实证明,我上面所说的可能会产生误导。我找到了困难的方法:

 Caused by: java.lang.IllegalArgumentException: Cannot bind argument at index 3 because the index is out of range.  The statement has 1 parameters.
        at android.database.sqlite.SQLiteProgram.bind(SQLiteProgram.java:212)
        at android.database.sqlite.SQLiteProgram.bindString(SQLiteProgram.java:166)
        at android.database.sqlite.SQLiteProgram.bindAllArgsAsStrings(SQLiteProgram.java:200)
        at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:47)
        at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1314)
        at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1161)
        at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1032)
        at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1200)

The above exception was thrown because I tried to pass selectionArgs which contained more elements than the number of ? placeholders in selection.

抛出上面的异常是因为我试图传递selectionArgs,其中包含的元素数多于?占位符在选择中。

These two methods from SQLiteProgram.java are to "blame" for this exception:

SQLiteProgram.java中的这两个方法是对这个异常的“责备”:

public void bindAllArgsAsStrings(String[] bindArgs) {
    if (bindArgs != null) {
        for (int i = bindArgs.length; i != 0; i--) {
            bindString(i, bindArgs[i - 1]);
        }
    }
}

private void bind(int index, Object value) {
    if (index < 1 || index > mNumParameters) {
        throw new IllegalArgumentException("Cannot bind argument at index "
                + index + " because the index is out of range.  "
                + "The statement has " + mNumParameters + " parameters.");
    }
    mBindArgs[index - 1] = value;
}

Now, when I found out about this behavior, I think that the code example from Android Developers site is not just inefficient, but is a total crap!

现在,当我发现这个行为时,我认为来自Android Developers网站的代码示例不仅效率低下,而且完全是废话!

Bottom line: if you pass null as selection, pass null as selectionArgs as well. If selection is not null and contains ? placeholders - make sure that the length of selectionArgs array equals the number of ? placeholders in selection.

底线:如果您将null作为选择传递,则也将null作为selectionArgs传递。如果选择不为null并包含?占位符 - 确保selectionArgs数组的长度等于?占位符在选择中。

#2


3  

I like it, because it's symmetric

我喜欢它,因为它是对称的

if something
    var = x
else
    var = y

It's clear what var is under each condition, without needing to go back and visit its initial value.

很清楚每个条件下的var是什么,无需返回并访问其初始值。

#1


2  

Except for additional clarity and code readability, as noted in another answer, this coding style makes for a less error prone code which is easier to maintain.

除了额外的清晰度和代码可读性之外,如另一个答案中所述,这种编码风格使得更容易出错的代码更容易维护。

This way, if the initial value of mSelectionArgs is changed, or new code added which overrides this value before the execution of the if-else block, the code of this block will still execute correctly. Without this "rudimentary" assignment, a change as described above could lead to a bug which would be very difficult to trace.

这样,如果更改了mSelectionArgs的初始值,或者添加了在执行if-else块之前覆盖此值的新代码,则此块的代码仍将正确执行。如果没有这种“基本”的分配,如上所述的改变可能会导致一个很难追查的错误。

As a side note:

作为旁注:

This specific code snippet is not that good (yes, I know it is from Android Developers site...) - if you pass null as selection argument to query(), then it is better to also pass null as selectionArgs argument. I'd modify this sample to something like this (setting both selection and selectionArgs to null):

这个特定的代码片段并不是那么好(是的,我知道它来自Android Developers网站......) - 如果你将null作为选择参数传递给query(),那么最好还将null作为selectionArgs参数传递。我将此示例修改为类似的内容(将selection和selectionArgs都设置为null):

// Gets a word from the UI

mSearchString = mSearchWord.getText().toString();

// Remember to insert code here to check for invalid or malicious input.

String[] mSelectionArgs = null;

// If the word is the empty string, gets everything
if (TextUtils.isEmpty(mSearchString)) {
    // Setting the selection clause to null will return all words
    mSelectionClause = null;
    mSelectionArgs = null;

} else {
    // Constructs a selection clause that matches the word that the user entered.
    mSelectionClause = UserDictionary.Words.WORD + " = ?";

    // Moves the user's input string to the selection arguments.
    mSelectionArgs = new String[] {mSearchString};

}

Edit: why the above code snippet is better than the original one?

编辑:为什么上面的代码片段比原来的更好?

It is not an error to pass null as selection and non-null as selectionArgs. This array will be passed to the specific ContentProvider you're addressing, and shouldn't be used at all since selection does not contain any ? placeholders. Any ContentProvider violating this assumption is buggy. Although not an error, it just looks weird - why do you pass an object that should be ignored anyway? This also has performance cost (which is higher if ContentProvider runs in different process), which is proportional to the size of the object being passed.

将null作为选择传递并将非null作为selectionArgs传递并不是错误。此数组将传递给您正在寻址的特定ContentProvider,并且根本不应该使用,因为选择不包含任何内容?占位符。违反此假设的任何ContentProvider都是错误的。虽然不是错误,但它看起来很奇怪 - 为什么你传递一个应该被忽略的对象?这也有性能成本(如果ContentProvider在不同的进程中运行,则会更高),这与传递的对象的大小成比例。

Edit 2: why the above code snippet is MUCH better than the original one? Turns out that what I said above might be misleading. I found it out the hard way:

编辑2:为什么上面的代码片段比原始代码片段好多了?事实证明,我上面所说的可能会产生误导。我找到了困难的方法:

 Caused by: java.lang.IllegalArgumentException: Cannot bind argument at index 3 because the index is out of range.  The statement has 1 parameters.
        at android.database.sqlite.SQLiteProgram.bind(SQLiteProgram.java:212)
        at android.database.sqlite.SQLiteProgram.bindString(SQLiteProgram.java:166)
        at android.database.sqlite.SQLiteProgram.bindAllArgsAsStrings(SQLiteProgram.java:200)
        at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:47)
        at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1314)
        at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1161)
        at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1032)
        at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1200)

The above exception was thrown because I tried to pass selectionArgs which contained more elements than the number of ? placeholders in selection.

抛出上面的异常是因为我试图传递selectionArgs,其中包含的元素数多于?占位符在选择中。

These two methods from SQLiteProgram.java are to "blame" for this exception:

SQLiteProgram.java中的这两个方法是对这个异常的“责备”:

public void bindAllArgsAsStrings(String[] bindArgs) {
    if (bindArgs != null) {
        for (int i = bindArgs.length; i != 0; i--) {
            bindString(i, bindArgs[i - 1]);
        }
    }
}

private void bind(int index, Object value) {
    if (index < 1 || index > mNumParameters) {
        throw new IllegalArgumentException("Cannot bind argument at index "
                + index + " because the index is out of range.  "
                + "The statement has " + mNumParameters + " parameters.");
    }
    mBindArgs[index - 1] = value;
}

Now, when I found out about this behavior, I think that the code example from Android Developers site is not just inefficient, but is a total crap!

现在,当我发现这个行为时,我认为来自Android Developers网站的代码示例不仅效率低下,而且完全是废话!

Bottom line: if you pass null as selection, pass null as selectionArgs as well. If selection is not null and contains ? placeholders - make sure that the length of selectionArgs array equals the number of ? placeholders in selection.

底线:如果您将null作为选择传递,则也将null作为selectionArgs传递。如果选择不为null并包含?占位符 - 确保selectionArgs数组的长度等于?占位符在选择中。

#2


3  

I like it, because it's symmetric

我喜欢它,因为它是对称的

if something
    var = x
else
    var = y

It's clear what var is under each condition, without needing to go back and visit its initial value.

很清楚每个条件下的var是什么,无需返回并访问其初始值。