字符串替换方法未替换字符。

86

我有一个作为字符串传递的句子,我正在将单词 "and" 替换为 " "。但它没有将单词 "and" 替换为空格。以下是我的逻辑示例。当我调试时,逻辑确实执行了sentence.replace。

String sentence = "Define, Measure, Analyze, Design and Verify"
if (sentence.contains("and")){
    sentence.replace("and", " ");
}

我是否漏掉了什么重要的东西?


36
字符串不可变。 - Matt Ball
5个回答

179

当我进行调试时,逻辑确实会进入 sentence.replace。

是的,然后你却废弃了返回值。

Java中的字符串是不可变的——当你调用replace方法时,它并不会改变现有字符串的内容——它会返回一个修改后的字符串。因此你需要这样写:

sentence = sentence.replace("and", " ");

这适用于String中的所有方法(substring,toLowerCase等)。它们中没有一个会更改字符串的内容。

请注意,在条件语句中你并不真正需要这样做 - 毕竟,如果句子不包含"and",执行替换也没有什么坏处:

String sentence = "Define, Measure, Analyze, Design and Verify";
sentence = sentence.replace("and", " ");

2
我必须指出你回答了一个重复的问题,而不是投票关闭它。这个问题已经被问过和回答过很多次了 - Jon,怎么回事? - Matt Ball
2
@MattBall 虽然我同意这个问题被反复问过,但我认为这是一个更好的答案,以我个人之见。 - MadProgrammer
20
@MattBall:常常发生这样的情况,我发现回答一个好的、完整的问题比寻找一个已有好答案的重复问题更快。我相信(虽然有些自负),这里我的答案比你找到的那个重复问题中被接受的答案更好,后者甚至在技术上都没有说服力。(“您需要使字符串实际等于您对字符串所做的更改” - 是什么意思?)此外,我想指出不需要先检查包含的方面。 - Jon Skeet
经过一段时间的思考,我觉得这是一个更好的答案。 - yams

69

字符串是不可变的,意味着其内容不能改变。当你调用replace(this,that)时,你得到一个全新的字符串。如果你想保留这个新拷贝,你需要将它赋值给一个变量。你可以覆盖旧的引用(类似于sentence = sentence.replace(this,that))或者创建一个新的引用如下所示:

public class Test{

    public static void main(String[] args) {

        String sentence = "Define, Measure, Analyze, Design and Verify";

        String replaced = sentence.replace("and", "");
        System.out.println(replaced);

    }
}
作为一个旁注,注意我已经删除了contains()检查,因为这里它是一个不必要的调用。如果它没有包含它,那么替换将无法进行任何替换。只有当你要替换的内容与你正在检查的实际条件不同时,才需要使用contains方法。

41
此答案的文字暗示了contains()调用是引起问题的原因,但实际上不是。这是一个不必要的调用,但它并没有导致任何问题。问题是由于忽略了replace的返回值而造成的,在该答案中根本没有解释这一点。 - Jon Skeet
@Mr.Jon Skeet,如果我的回答中的文本暗示了另一种方式,我真的很抱歉...但是当我说不需要时,我是指它是不必要的...好的,我会在答案中包含它,使其更明显... - Kumar Vivek Mitra
如果你这样做:sentence.replace(" and", ",");,会不会更好呢? - Khaled.K
@JonSkeet 和其他人 - 我添加了一个解释正在发生什么的段落,并将误导性文本移到了末尾,因为它对实际问题而言相当多余。 - corsiKa
3
说实话,如果是在别人已经回答的内容上进行编辑,我不会这样做。这将会极大地改变答案的意思。 - Jon Skeet

9

您没有对replace的返回值进行任何操作。您需要将该方法的结果赋值给新的String:

sentence = sentence.replace("and", " ");

在Java中,String是不可变的。例如像replace这样的方法会返回一个新的String

你的contains测试是不必要的:如果没有要替换的文本实例,replace方法就会无操作。


我的代码需要包含逻辑,因为有些情况下我不想替换它。这个逻辑并不完全像这样,我只是举了一个例子。 - yams
@MarkBasler:你的代码逻辑在你提供的示例中并不需要,所以你不应该包含它。好的问题应该只包含必要展示问题的内容-通过包含在你提供的情况下毫无意义的代码,你已经给问题增加了一个干扰因素。 - Jon Skeet
我关注的是包含,我关注的是替换。 - yams
顺便标记一下它为重复并回答它。保持优雅。 - yams
嗨@MarkBasler:我试图提供帮助。我没有看到两个操作之间有冲突:你的问题是一个非常常见的问题,经常被问到:Java字符串是不可变的。当我将一个问题标记为重复时,我是为了提高这里的问题和答案的质量,但同时,留下一个针对你问题的具体回答,我的希望是提供更即时的帮助,与你的示例相关。你可能会发现这个meta问题有用。 - pb2q

8
你应该重新分配替换的结果,像这样:

你需要重新赋值替换后的结果,如下所示:

 sentence = sentence.replace("and", " ");

请注意,String类是不可变对象,这意味着它的所有方法都返回一个新字符串并且从不直接修改原始字符串,因此调用String实例中的方法的结果必须分配给一个变量或立即使用以使更改生效。


字符串应该是不可变的,但是在字符串库中存在一些错误,允许您修改原始字符串。 - yams
4
@MarkBasler:嗯,你到底在说哪些错误?如果你知道字符串是不可变的,那么不清楚为什么你还期望你的代码可以正常运行... - Jon Skeet

-1
package com.tulu.ds;

public class EmailSecurity {
    public static void main(String[] args) {
        System.out.println(returnSecuredEmailID("sample717@gmail.com"));
    }
    private static String returnSecuredEmailID(String email){
        String str=email.substring(1, email.lastIndexOf("@")-1);
        return email.replaceAll(email.substring(1, email.lastIndexOf("@")-1),replacewith(str.length(),"*"));
    }
    private static String replacewith(int length,String replace) {
        String finalStr="";
        for(int i=0;i<length;i++){
            finalStr+=replace;
        }
        return finalStr;
    }   
}

3
请勿仅提供代码答案,而是解释您的代码如何解决问题。来自审核 - Taku

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接