使用replaceAll()修改现有元素时,列表不会更新

时间:2020-10-28 14:06:21

标签: java

这是我的代码:

List<String> l1 = new ArrayList<>(); 

l1.add("one");
l1.add("two");
l1.add("three");
l1.add("four");
  
for(String str : l1){
    if(str.equals("four")){
     str = str.replaceAll(str,"five");
    }
}
System.out.println(l1);

如您所见,我使用了replaceAll(),并期望输出为[one,two,three,five],但显示为[one,two,three,four]

尽管我检查了str等同于"four",但应将其替换为"five",但不会更新列表。我在做什么错了?

5 个答案:

答案 0 :(得分:1)

您可能要使用List::replaceAll方法:

List<String> list = Arrays.asList("one", "two", "three", "four", "five");
list.replaceAll(s -> s.equals("four") ? "five" : s);

System.out.println(list);

输出:

[one, two, three, five, five]

答案 1 :(得分:1)

如果您使用的是Java 8或更高版本,请执行answer by Alex Rudenko中所示的操作:

您可能要使用List::replaceAll方法:

List<String> list = Arrays.asList("one", "two", "three", "four", "five");
list.replaceAll(s -> s.equals("four") ? "five" : s);

System.out.println(list);

输出:

[one, two, three, five, five]

否则请使用ListIterator

for (ListIterator<String> iter = list.listIterator(); iter.hasNext(); ) {
    String s = iter.next();
    if (s.equals("four"))
        iter.set("five");
}

可以使用索引循环,如另一个答案所示,但是在某些List实现中,例如LinkedList,因此不推荐使用。即使当前已知列表为ArrayList,将来也可能会更改,因此请为其提供更好的代码。

// I don't recommend this
for (int i = 0; i < list.size(); i++)
    if (list.get(i).equals("four"))
        list.set(i, "five");

答案 2 :(得分:0)

我建议以这种方式遍历列表:

  public static void main(String[] args) {

   ArrayList<String> strings = new ArrayList<>();
   strings.add("one");
   strings.add("two");
   strings.add("three");
   strings.add("four");
   for (int i = 0; i < strings.size(); i++) {
     if(strings.get(i).equals("four")) {
       strings.set(i, "five");
     }
   }

   System.out.println(strings);
  }

您的解决方案失败,因为replaceAll返回一个字符串,您将该字符串放入str中,然后在您实际上希望将“ four”元素设置为新值时不对其进行任何操作。

答案 3 :(得分:0)

Java的设计工作正常,所以让我尝试解释为什么以及如何以这种方式工作。

字符串是对象。

任何对象类型的变量(因此,intdouble和其他6个原语以外的所有变量)都是引用

参考就像藏宝图。 X标记该点。

物体就像宝藏。

x = foo是您要清除藏宝图并绘制一张新藏宝图。如果x是某个宝藏的地图,此后,该宝藏完全不受影响-您所做的全部工作将清除您的宝藏地图,并用指向其他宝藏的地图覆盖(而且那个宝藏也不受影响)。我们只是在弄乱这里的地图,而不是与宝藏。

x.foo()-用点(.)在Java中表示“跟随地图并向下挖掘”。这将“发送消息”到对象,并且可能会或可能不会影响该对象。这取决于方法。 "hello".length()之类的东西不会更改字符串。像myObj.setName("Joe");之类的东西肯定会改变您的myObj藏宝图所映射到的藏宝。

str.replaceAll 不更改宝藏。该方法将创建一个全新的宝物,它是您向其发送消息的宝物的副本,但已应用替代品。这是因为字符串对象是java.lang.String的方法不可变-。通过设计。这就是replaceAll首先返回字符串(将是修改后的克隆)的原因。

所以,要逐行通过它:

  1. for (String str : l1)

这是说:拿一张新的空白纸并将this is called str放在顶部。然后,以您现有的名为l1的藏宝图,跟随它并进行挖掘。它包含4个藏宝图(一个藏宝“一个”,一个藏宝“两个”,等等)。对于您在此处找到的每张地图,将地图复制到标记为str的全新空白纸上,清除其中的所有内容,然后在{}中运行代码。

  1. str = str.replaceAll(str, "five");

这是说:按照您的str地图进行挖掘。然后,清除您的str地图,要求该宝藏对其自身进行修改后的克隆并埋在沙子中,然后更新str地图以指向该新宝藏。

  1. }}-关闭if和for

我们现在返回顶部,这意味着您修改后的藏宝图被丢弃了,因此克隆的藏宝图了吗?没有人有地图了。它迷失在沙子里。最终,垃圾收集器将摆脱它。

好的,我该如何解决

通过致电l1.set()l1.add()

或者,确保您的列表由可变对象组成并对其进行突变。 StringBuilder是一个可变的类似字符串的概念,您可以使用它。

补充说明

即使解决了列表问题,代码仍然被破坏。 replaceAll是一个非常糟糕的方法。它的第一个参数被解释为正则表达式。你不要那样您正在寻找replace。此会替换所有出现的内容,但它不会尝试将needle参数(第一个参数)解释为正则表达式,只是将其视为原始字符。当然,更一般地说,str = str.replace(str, "five");最好写成str = "five";

但是...为什么Java这样工作??

让我们回到弦乐宝藏上。正如我所说,没有一种方法可以改变它。这意味着您可以毫无保留地分发您的藏宝图副本,而不用担心谁会得到它的副本。您的财宝不受损害。它不能被移动,破坏或以其他方式弄乱。

那是一件好事,因为如果其他代码可能使它混乱,那么要么我不得不花费大量的精力来证明您如何无法破坏我的财宝或代码中断,要么,我必须克隆每次我需要将珍宝传递给某人时(每次将字符串作为参数传递给另一个方法,或者返回字符串时,都将您的藏宝图的副本传递给其他人)。所有这些副本浪费的时间和内存绝对是个大问题!

如果您认为不是所有人都在谈论藏宝图,而是所有人都在谈论藏宝本身,那您会认为Java会更简单。这是:String hello = "gold"; x.foo(hello);意味着我的代码复制了一个藏宝图,如果您遵循它,将导致其中带有"gold"的藏宝箱。但是,如果我不把所有这些杂乱的地图弄乱,而是将整个藏宝箱移交给我怎么办?

这里的问题是:(可能)有很多内存,并且由于hello变量在调用x.foo(hello);之后不会消失,因此整个复制方面都必须保留,所以您设计会成为一种语言,在这种语言中,我们会大量克隆宝藏。

那很糟糕。宝藏图易于复制-确保它们是64位(或更小,在32位VM上,并且具有VM可以执行的压缩OOPS技巧)。百宝箱可能大小为千兆字节。

这就是为什么Java没有内置的方式来克隆宝藏,而是始终克隆宝藏地图的原因。

答案 4 :(得分:0)

不清楚是要替换所有匹配项还是仅替换第一个匹配项。仅当您只想替换第一次出现的情况时,才使用此解决方案。

List#indexOf返回此列表中指定元素的首次出现的索引,如果此列表不包含元素,则返回- 1。您可以使用此功能来完成这项工作:

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> l1 = new ArrayList<>();

        l1.add("one");
        l1.add("two");
        l1.add("three");
        l1.add("four");

        int index = l1.indexOf("four");
        if (index != -1) {
            l1.set(index, "five");
        }

        System.out.println(l1);
    }
}

输出:

[one, two, three, five]
相关问题