MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Java中String常用方法的高效使用技巧

2022-12-065.4k 阅读

1. length() 方法

length() 方法用于返回字符串的长度。它是一个非常基础且常用的方法,其实现原理相对简单。在 String 类内部,有一个 char 数组来存储字符串的字符,length() 方法实际上就是返回这个数组的长度。

示例代码如下:

public class StringLengthExample {
    public static void main(String[] args) {
        String str = "Hello, World!";
        int length = str.length();
        System.out.println("字符串的长度为: " + length);
    }
}

在这个例子中,我们创建了一个字符串 Hello, World!,然后调用 length() 方法获取其长度并打印出来。这个方法的时间复杂度是 O(1),因为它只是简单地返回内部数组的长度,不涉及任何循环或复杂的计算。

2. charAt(int index) 方法

charAt(int index) 方法用于返回指定索引位置的字符。索引从 0 开始,取值范围是 0 到 length() - 1。如果索引超出这个范围,会抛出 StringIndexOutOfBoundsException 异常。

其实现原理也是基于内部的 char 数组,通过索引直接从数组中获取对应的字符。

示例代码:

public class StringCharAtExample {
    public static void main(String[] args) {
        String str = "Java";
        char ch = str.charAt(2);
        System.out.println("索引为2的字符是: " + ch);
    }
}

在上述代码中,我们获取字符串 Java 中索引为 2 的字符并打印。这里要注意的是,在使用 charAt 方法时,一定要确保索引在有效范围内,否则程序会因为异常而终止。

3. substring(int beginIndex) 和 substring(int beginIndex, int endIndex) 方法

3.1 substring(int beginIndex)

substring(int beginIndex) 方法用于返回从指定索引 beginIndex 开始到字符串末尾的子字符串。

示例代码:

public class StringSubstring1Example {
    public static void main(String[] args) {
        String str = "Hello, World!";
        String subStr = str.substring(7);
        System.out.println("子字符串是: " + subStr);
    }
}

在这个例子中,我们从索引 7 开始截取字符串,得到子字符串 World!

3.2 substring(int beginIndex, int endIndex)

substring(int beginIndex, int endIndex) 方法用于返回从 beginIndex 开始(包括)到 endIndex 结束(不包括)的子字符串。

示例代码:

public class StringSubstring2Example {
    public static void main(String[] args) {
        String str = "Hello, World!";
        String subStr = str.substring(0, 5);
        System.out.println("子字符串是: " + subStr);
    }
}

这里从索引 0 开始截取到索引 5 之前(不包括 5),得到子字符串 Hello。需要注意的是,beginIndex 必须小于等于 endIndex,且 endIndex 不能超过字符串的长度,否则会抛出 StringIndexOutOfBoundsException 异常。

String 类的实现中,substring 方法并没有创建一个全新的字符数组来存储子字符串的内容,而是通过共享原字符串的 char 数组,并设置不同的偏移量和长度来实现子字符串的表示。这在一定程度上节省了内存,但也可能会导致一些潜在的问题,比如原字符串被垃圾回收时,子字符串可能还在使用,从而影响性能。从 Java 7u6 开始,substring 方法的实现进行了优化,不再共享原数组,而是创建一个新的数组来存储子字符串,避免了这种潜在的性能问题。

4. equals(Object obj) 和 equalsIgnoreCase(String anotherString) 方法

4.1 equals(Object obj)

equals(Object obj) 方法用于比较两个字符串的内容是否相等。它会先判断传入的对象是否为 String 类型,如果不是则直接返回 false。如果是 String 类型,再逐个字符地比较两个字符串的内容。

示例代码:

public class StringEqualsExample {
    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = "Hello";
        String str3 = "hello";
        boolean isEqual1 = str1.equals(str2);
        boolean isEqual2 = str1.equals(str3);
        System.out.println("str1 和 str2 是否相等: " + isEqual1);
        System.out.println("str1 和 str3 是否相等: " + isEqual2);
    }
}

在上述代码中,str1str2 内容相同,equals 方法返回 true;而 str1str3 虽然字符相同但大小写不同,equals 方法返回 false

4.2 equalsIgnoreCase(String anotherString)

equalsIgnoreCase(String anotherString) 方法与 equals 方法类似,只是它在比较时忽略大小写。

示例代码:

public class StringEqualsIgnoreCaseExample {
    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = "hello";
        boolean isEqual = str1.equalsIgnoreCase(str2);
        System.out.println("str1 和 str2 是否相等(忽略大小写): " + isEqual);
    }
}

这里 str1str2 虽然大小写不同,但 equalsIgnoreCase 方法返回 true。在实现上,equalsIgnoreCase 方法会将两个字符串中的字符统一转换为大写或小写后再进行比较。

5. compareTo(String anotherString) 和 compareToIgnoreCase(String str) 方法

5.1 compareTo(String anotherString)

compareTo(String anotherString) 方法用于按字典顺序比较两个字符串。它返回一个整数值,如果当前字符串小于 anotherString,返回负整数;如果相等,返回 0;如果当前字符串大于 anotherString,返回正整数。

示例代码:

public class StringCompareToExample {
    public static void main(String[] args) {
        String str1 = "apple";
        String str2 = "banana";
        String str3 = "apple";
        int result1 = str1.compareTo(str2);
        int result2 = str1.compareTo(str3);
        System.out.println("str1 与 str2 的比较结果: " + result1);
        System.out.println("str1 与 str3 的比较结果: " + result2);
    }
}

在这个例子中,由于 apple 在字典顺序上小于 bananacompareTo 方法返回一个负整数;而 str1str3 内容相同,返回 0。

5.2 compareToIgnoreCase(String str)

compareToIgnoreCase(String str) 方法与 compareTo 方法类似,只是在比较时忽略大小写。

示例代码:

public class StringCompareToIgnoreCaseExample {
    public static void main(String[] args) {
        String str1 = "Apple";
        String str2 = "apple";
        int result = str1.compareToIgnoreCase(str2);
        System.out.println("str1 与 str2 的比较结果(忽略大小写): " + result);
    }
}

这里 str1str2 虽然大小写不同,但忽略大小写后内容相同,compareToIgnoreCase 方法返回 0。

6. indexOf(int ch) 和 indexOf(String str) 方法

6.1 indexOf(int ch)

indexOf(int ch) 方法用于返回指定字符 ch 在字符串中第一次出现的索引位置。如果不存在该字符,则返回 -1。

示例代码:

public class StringIndexOfCharExample {
    public static void main(String[] args) {
        String str = "Hello, World!";
        int index = str.indexOf('o');
        System.out.println("字符 'o' 第一次出现的索引位置: " + index);
    }
}

在上述代码中,字符 o 第一次出现在索引 4 的位置。

6.2 indexOf(String str)

indexOf(String str) 方法用于返回指定子字符串 str 在字符串中第一次出现的索引位置。如果不存在该子字符串,则返回 -1。

示例代码:

public class StringIndexOfStringExample {
    public static void main(String[] args) {
        String str = "Hello, World!";
        int index = str.indexOf("World");
        System.out.println("子字符串 'World' 第一次出现的索引位置: " + index);
    }
}

这里子字符串 World 第一次出现在索引 7 的位置。这两个方法都是从字符串的开头开始查找,实现时采用了简单的线性查找算法,时间复杂度为 O(n),其中 n 是字符串的长度。

7. lastIndexOf(int ch) 和 lastIndexOf(String str) 方法

7.1 lastIndexOf(int ch)

lastIndexOf(int ch) 方法用于返回指定字符 ch 在字符串中最后一次出现的索引位置。如果不存在该字符,则返回 -1。与 indexOf(int ch) 方法不同的是,它是从字符串的末尾开始向前查找。

示例代码:

public class StringLastIndexOfCharExample {
    public static void main(String[] args) {
        String str = "Hello, World!";
        int index = str.lastIndexOf('o');
        System.out.println("字符 'o' 最后一次出现的索引位置: " + index);
    }
}

在这个例子中,字符 o 最后一次出现在索引 8 的位置。

7.2 lastIndexOf(String str)

lastIndexOf(String str) 方法用于返回指定子字符串 str 在字符串中最后一次出现的索引位置。如果不存在该子字符串,则返回 -1。同样是从字符串的末尾开始向前查找。

示例代码:

public class StringLastIndexOfStringExample {
    public static void main(String[] args) {
        String str = "Hello, World! Hello, Java!";
        int index = str.lastIndexOf("Hello");
        System.out.println("子字符串 'Hello' 最后一次出现的索引位置: " + index);
    }
}

这里子字符串 Hello 最后一次出现在索引 13 的位置。这两个方法同样采用线性查找算法,时间复杂度为 O(n)。

8. contains(CharSequence s) 方法

contains(CharSequence s) 方法用于判断当前字符串是否包含指定的字符序列 s。它实际上是通过调用 indexOf 方法来实现的,如果 indexOf 方法返回的索引不是 -1,则表示包含该字符序列,返回 true,否则返回 false

示例代码:

public class StringContainsExample {
    public static void main(String[] args) {
        String str = "Hello, World!";
        boolean contains = str.contains("World");
        System.out.println("字符串是否包含 'World': " + contains);
    }
}

在上述代码中,字符串 Hello, World! 包含子字符串 World,所以 contains 方法返回 true

9. replace(char oldChar, char newChar) 和 replace(CharSequence target, CharSequence replacement) 方法

9.1 replace(char oldChar, char newChar)

replace(char oldChar, char newChar) 方法用于将字符串中所有的 oldChar 替换为 newChar,并返回一个新的字符串。原字符串并不会被修改,因为 String 类是不可变的。

示例代码:

public class StringReplaceCharExample {
    public static void main(String[] args) {
        String str = "Hello, World!";
        String newStr = str.replace('o', '0');
        System.out.println("替换后的字符串: " + newStr);
    }
}

在这个例子中,我们将字符串中的 o 替换为 0,得到新字符串 Hell0, W0rld!

9.2 replace(CharSequence target, CharSequence replacement)

replace(CharSequence target, CharSequence replacement) 方法用于将字符串中所有的 target 子字符串替换为 replacement 子字符串,并返回一个新的字符串。

示例代码:

public class StringReplaceStringExample {
    public static void main(String[] args) {
        String str = "Hello, World!";
        String newStr = str.replace("World", "Java");
        System.out.println("替换后的字符串: " + newStr);
    }
}

这里将 World 替换为 Java,得到新字符串 Hello, Java!。这两个 replace 方法在实现时,会遍历原字符串,根据需要替换的字符或子字符串进行替换操作,然后构建一个新的字符串返回。

10. split(String regex) 和 split(String regex, int limit) 方法

10.1 split(String regex)

split(String regex) 方法用于根据指定的正则表达式 regex 将字符串拆分为字符串数组。

示例代码:

public class StringSplitExample1 {
    public static void main(String[] args) {
        String str = "apple,banana,orange";
        String[] parts = str.split(",");
        for (String part : parts) {
            System.out.println(part);
        }
    }
}

在上述代码中,我们以逗号 , 作为分隔符,将字符串拆分为三个部分并打印出来。

10.2 split(String regex, int limit)

split(String regex, int limit) 方法与 split(String regex) 方法类似,但它可以指定拆分的最大次数 limit。如果 limit 大于 0,最多拆分 limit - 1 次,数组的长度不会超过 limit,并且数组的最后一个元素会包含剩余的所有字符;如果 limit 为 0,会尽可能多地拆分,并且丢弃末尾的空字符串;如果 limit 为负数,会尽可能多地拆分,并且保留末尾的空字符串。

示例代码:

public class StringSplitExample2 {
    public static void main(String[] args) {
        String str = "apple,banana,orange";
        String[] parts1 = str.split(",", 2);
        String[] parts2 = str.split(",", 0);
        String[] parts3 = str.split(",", -1);
        System.out.println("limit 为 2 时的拆分结果:");
        for (String part : parts1) {
            System.out.println(part);
        }
        System.out.println("limit 为 0 时的拆分结果:");
        for (String part : parts2) {
            System.out.println(part);
        }
        System.out.println("limit 为 -1 时的拆分结果:");
        for (String part : parts3) {
            System.out.println(part);
        }
    }
}

在这个例子中,limit 为 2 时,只拆分一次,得到两个元素的数组;limit 为 0 时,丢弃末尾可能的空字符串;limit 为 -1 时,保留末尾的空字符串。

11. toUpperCase() 和 toLowerCase() 方法

11.1 toUpperCase()

toUpperCase() 方法用于将字符串中的所有字符转换为大写形式,并返回一个新的字符串。

示例代码:

public class StringToUpperCaseExample {
    public static void main(String[] args) {
        String str = "hello, world!";
        String upperStr = str.toUpperCase();
        System.out.println("转换为大写后的字符串: " + upperStr);
    }
}

这里将字符串 hello, world! 转换为 HELLO, WORLD!

11.2 toLowerCase()

toLowerCase() 方法用于将字符串中的所有字符转换为小写形式,并返回一个新的字符串。

示例代码:

public class StringToLowerCaseExample {
    public static void main(String[] args) {
        String str = "HELLO, WORLD!";
        String lowerStr = str.toLowerCase();
        System.out.println("转换为小写后的字符串: " + lowerStr);
    }
}

此例中,将字符串 HELLO, WORLD! 转换为 hello, world!。这两个方法在实现时,会根据字符的 Unicode 编码规则进行大小写转换。

12. trim() 方法

trim() 方法用于去除字符串两端的空白字符(包括空格、制表符、换行符等),并返回一个新的字符串。

示例代码:

public class StringTrimExample {
    public static void main(String[] args) {
        String str = "   Hello, World!   ";
        String trimmedStr = str.trim();
        System.out.println("去除两端空白后的字符串: " + trimmedStr);
    }
}

在上述代码中,将字符串两端的空白字符去除,得到 Hello, World!trim 方法的实现是通过扫描字符串的两端,找到第一个和最后一个非空白字符的位置,然后截取这两个位置之间的字符形成新的字符串。

13. join(CharSequence delimiter, CharSequence... elements) 方法

join(CharSequence delimiter, CharSequence... elements) 方法是 Java 8 引入的静态方法,用于将多个字符序列用指定的分隔符连接起来,形成一个新的字符串。

示例代码:

public class StringJoinExample {
    public static void main(String[] args) {
        String result = String.join(", ", "apple", "banana", "orange");
        System.out.println("连接后的字符串: " + result);
    }
}

在这个例子中,我们使用逗号和空格作为分隔符,将 applebananaorange 连接起来,得到 apple, banana, orange。该方法的实现原理是通过 StringBuilder 类来构建最终的字符串,这样可以提高连接操作的效率,避免了使用 + 运算符在循环中连接字符串可能导致的性能问题。

14. format(String format, Object... args) 方法

format(String format, Object... args) 方法用于使用指定的格式字符串和参数来格式化字符串,返回一个格式化后的新字符串。它类似于 C 语言中的 printf 函数。

示例代码:

public class StringFormatExample {
    public static void main(String[] args) {
        String name = "Alice";
        int age = 30;
        String message = String.format("姓名:%s,年龄:%d", name, age);
        System.out.println("格式化后的字符串: " + message);
    }
}

在上述代码中,我们使用 %s 表示字符串类型的参数,%d 表示整数类型的参数,将 nameage 按照指定格式插入到字符串中,得到 姓名:Alice,年龄:30。格式字符串中的占位符还有很多,如 %f 用于浮点数,%c 用于字符等,可以根据实际需求灵活使用。

15. intern() 方法

intern() 方法用于将字符串对象添加到字符串常量池中。如果字符串常量池中已经存在相同内容的字符串,则返回常量池中的字符串;否则,将当前字符串添加到常量池,并返回该字符串。

示例代码:

public class StringInternExample {
    public static void main(String[] args) {
        String str1 = new String("Hello");
        String str2 = str1.intern();
        String str3 = "Hello";
        System.out.println(str1 == str2); // false
        System.out.println(str2 == str3); // true
    }
}

在这个例子中,str1 是通过 new 关键字创建的字符串对象,在堆内存中;调用 intern() 方法后,str2 指向了字符串常量池中的 Hello 字符串;str3 直接指向字符串常量池中的 Hello 字符串。所以 str1str2 不相等(因为它们指向不同的内存位置),而 str2str3 相等。使用 intern() 方法可以在一定程度上节省内存,特别是在处理大量重复字符串时,但需要注意它可能带来的性能开销,因为字符串常量池的维护也需要一定的资源。

通过深入了解这些 String 常用方法的本质和高效使用技巧,我们在实际编程中可以更加灵活、高效地处理字符串相关的操作,提高程序的性能和可读性。同时,在使用这些方法时,要根据具体的场景和需求进行合理选择,避免因不当使用而导致的性能问题或逻辑错误。例如,在处理大量字符串连接操作时,应优先考虑使用 StringBuilderStringBuffer 类,而不是频繁使用 + 运算符或 concat 方法;在进行字符串比较时,要明确是需要严格区分大小写还是忽略大小写等。总之,对这些方法的熟练掌握和合理运用是 Java 编程中处理字符串的关键。