Java字符串编程:从基础到高效实践

在Java编程中,String 是最常用的类。因此,在Java面试中,经常会通过考察字符串程序来评估候选人的编码能力。

使用Java编写字符串程序

在这里,我将提供一些Java字符串编程示例,帮助您提升编码技能。在查看答案之前,请尝试自己解决这些问题,以获得更好的学习效果。我已尽力使用Java中引入的所有最新功能,如流(Stream)、Lambda表达式和函数式接口等。

如何在一个字符串中获取不同字符及其数量?

package com.Olivia.java.string;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class DistinctCharsCount {

	public static void main(String[] args) {

		printDistinctCharsWithCount("abc");
		printDistinctCharsWithCount("abcab3");
		printDistinctCharsWithCount("hi there, i am scdev");
	}

	private static void printDistinctCharsWithCount(String input) {
		Map<Character, Integer> charsWithCountMap = new HashMap<>();

		// 使用Java 8的Map merge方法
		for (char c : input.toCharArray())
			charsWithCountMap.merge(c, 1, Integer::sum);
		System.out.println(charsWithCountMap);

		// 另一种使用最新Java增强功能且不使用for循环的方法,但略显复杂
		List<Character> list = input.chars().mapToObj(c -> (char) c).collect(Collectors.toList());

		list.stream().forEach(c -> charsWithCountMap.merge(c, 1, Integer::sum));

		System.out.println(charsWithCountMap);

	}

}

请编写一个Java程序,用于反转字符串。

有许多方法可以反转一个字符串。其中一些常见的方法包括:

  • 使用 StringBuilder/StringBufferreverse() 方法
  • 使用字符/字节数组并反向遍历,然后构建结果字符串

然而,如果您不确定输入字符串的内容,始终建议使用 StringBuilder 内置的 reverse() 方法。因为使用字符和字节数组可能会产生意想不到的结果。我在《Java中的字符串反转》中对此进行了详细解释。

package com.Olivia.java.string;

public class ReverseAString {

	public static void main(String[] args) {

		reverseInputString("abc");
		reverseInputString("ç©∆˙¨˚ø"); //特殊字符
	}

	private static void reverseInputString(String input) {
		StringBuilder sb = new StringBuilder(input);
		String result = sb.reverse().toString();
		System.out.println(result);
	}

}

如何检查一个字符串是否为回文?

回文字符串是指其反转后仍然是同一个字符串。因此,我们可以将输入的字符串反转,并检查两个字符串是否相等。或者,我们可以巧妙地使用 StringcharAt(int index) 方法来检查回文字符串。

package com.Olivia.java.string;

public class PalindromeString {

	public static void main(String[] args) {
		
		checkPalindromeString("abc");
		checkPalindromeString("abcba");
		checkPalindromeString("ç∂©∂ç");
	}

	private static void checkPalindromeString(String input) {
		boolean result = true;
		int length = input.length();
		for(int i=0; i < length/2; i++) {
			if(input.charAt(i) != input.charAt(length-i-1)) {
				result = false;
				break;
			}
		}
		System.out.println(input + " is palindrome = "+result);
		
	}

}

如何从输入字符串中删除所有给定字符的出现?

String 类中没有直接的删除函数,但在这种情况下我们可以使用 replaceAll() 方法。下面是演示如何操作的简单程序。

package com.Olivia.java.string;

public class RemoveCharFromString {

	public static void main(String[] args) {

		removeCharFromString("abcbcdjfkd", 'c');
		removeCharFromString("Pankaj", 'a');
		removeCharFromString("ç∂©∂ç", '©');

	}

	private static void removeCharFromString(String input, char c) {
		String result = input.replaceAll(String.valueOf(c), "");
		System.out.println(result);
	}

}

如何在程序中证明字符串是不可变的?

我们都知道在Java中 String 是不可变的,但是新手开发者仍然会对此感到困惑。让我们试着理解这种困惑的原因。

String s1 = "Java";

s1 = "Python"; 

在上面的代码片段中,我们可能会认为 s1 的值发生了改变,它是一个 String 对象。那么我们如何说 String 是不可变的呢?最重要的一点是要理解在Java中如何创建字符串。当我们使用字符串字面量创建一个字符串时,它不会改变原始字符串的值。它会在字符串常量池中创建一个新的字符串,并改变变量的引用。因此,原始字符串的值永远不会改变,这就是为什么 String 是不可变的。下面的程序证明了我们的说法,请阅读注释以正确理解这个概念。

package com.Olivia.java.string;

public class StringImmutabilityTest {

	public static void main(String[] args) {

		String s1 = "Java"; // "Java" 字符串在常量池中创建,并将其引用赋值给 s1
		
		String s2 = s1; // s2 也指向常量池中 "Java" 的相同引用
		
		System.out.println(s1 == s2); // 证明 s1 和 s2 具有相同的引用
		
		s1 = "Python"; 
		// s1 的值在上面改变了,那么 String 怎么还是不可变的呢?
		
		// 其实,在上述情况下,一个新的字符串 "Python" 在常量池中被创建了
		// s1 现在指向常量池中的新字符串
		// 但是,原始字符串 "Java" 仍然未被改变,并保留在常量池中
		// s2 仍然指向常量池中的原始字符串 "Java"
		
		// 证明 s1 和 s2 具有不同的引用
		System.out.println(s1 == s2); 
		
		System.out.println(s2); 
		// 打印 "Java",支持原始字符串值未改变的事实,因此 String 是不可变的
		
	}

}

编写一个程序来统计字符串中的单词数量。

这个程序的简单解决方法似乎是 input.split(" ").length,但如果您的字符串格式不正确,包含前导和尾随空格、重复的多个空格和制表符,这种方法就不可行了。幸运的是,Stringsplit() 函数接受正则表达式作为参数,我们可以利用它来计算字符串中单词的数量。

这是文章《在Java中编写字符串程序》的第2部分(共3部分)。

package com.Olivia.java.string;

public class CountNumberOfWordsInString {
	public static void main(String[] args) {
		countNumberOfWords("My name is Pankaj");
		countNumberOfWords("I Love Java Programming");
		countNumberOfWords(" This	is  not   properly formatted		line ");
	}

	private static void countNumberOfWords(String line) {
		//System.out.println(line.split(" ").length); //won't work with tabs and multiple spaces
		String trimmedLine = line.trim();
		int count = trimmedLine.isEmpty() ? 0 : trimmedLine.split("\\s+").length;
		System.out.println(count);
	}
}

编写一个程序来检查两个字符串是否由相同的字符组成?

首先,我们需要从输入的字符串中创建字符集合。然后,使用字符集合的equals()方法来检查它们是否包含相同的字符。这是一个简单的程序,用于检查两个字符串是否由相同的字符组成。

package com.Olivia.java.string;

import java.util.Set;
import java.util.stream.Collectors;

public class CheckSameCharsInString {

	public static void main(String[] args) {
		sameCharsStrings("abc", "cba");
		sameCharsStrings("aabbcc", "abc");
		sameCharsStrings("abcd", "abc");
		sameCharsStrings("11", "1122");
		sameCharsStrings("1122", "11");	
	}

	private static void sameCharsStrings(String s1, String s2) {

		Set<Character> set1 = s1.chars().mapToObj(c -> (char) c).collect(Collectors.toSet());
		Set<Character> set2 = s2.chars().mapToObj(c -> (char) c).collect(Collectors.toSet());
		System.out.println(set1.equals(set2));
	}
}

读取两个字符串的用户输入,并检查第一个字符串是否包含第二个字符串?

这是一个简单的程序,我们可以使用Stringcontains()方法来检查指定的字符串是否是该字符串的一部分。然而,我们将需要使用Scanner类来读取用户的输入。

package com.Olivia.java.string;

import java.util.Scanner;

public class StringContainsSubstring {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		System.out.println("Enter First String:");
		String s1 = scanner.nextLine();
		
		System.out.println("Enter Second String:");
		String s2 = scanner.nextLine();
		
		scanner.close();
		
		boolean result = stringContainsSubstring(s1, s2);
		System.out.println(s1+" contains "+s2+" = "+result);
	}

	private static boolean stringContainsSubstring(String string, String substring) {
		boolean result = false;
		result = string.contains(substring);
		return result;
	}
}

以下是上述程序的样本输出:

Enter First String:
Pankaj
Enter Second String:
an
Pankaj contains an = true

如何在不使用第三个变量的情况下交换两个字符串?

我们可以使用Stringsubstring()方法来实现。以下是一个简单的代码片段来展示这一点。

String s1 = "abc";
String s2 = "def";

s1 = s1.concat(s2);
s2 = s1.substring(0,s1.length()-s2.length());
s1 = s1.substring(s2.length());

如果我们必须编写一个函数来执行此操作,该怎么办?由于String是不可变的,方法中String引用的值的改变将在方法结束时消失。此外,在Java中,我们无法从一个方法中返回多个对象。因此,我们将不得不创建一个容器来容纳输入的字符串,然后在方法中执行上述逻辑。下面的代码显示了如何实现这一点,虽然可能看起来复杂,但逻辑与上面的相同。

package com.Olivia.java.string;

import java.util.Scanner;

public class SwapTwoStrings {

	public static void main(String[] args) {
		
		Container container = new Container();
		Scanner scanner = new Scanner(System.in);
		System.out.println("Enter First String:");
		container.setFirstString(scanner.nextLine());
		
		System.out.println("Enter Second String:");
		container.setSecondString(scanner.nextLine());
		scanner.close();
		System.out.println(container);
		container = swapStrings(container);
		System.out.println(container);
	}

	private static Container swapStrings(Container container) {
		container.setFirstString(container.getFirstString().concat(container.getSecondString())); //s1 = s1+s2
		container.setSecondString(container.getFirstString().substring(0, container.getFirstString().length()-container.getSecondString().length())); // s2=s1
		container.setFirstString(container.getFirstString().substring(container.getSecondString().length()));
		return container;
	}
}

class Container{
	private String firstString;
	private String secondString;
	
	public String getFirstString() {
		return firstString;
	}
	public void setFirstString(String firstString) {
		this.firstString = firstString;
	}
	public String getSecondString() {
		return secondString;
	}
	public void setSecondString(String secondString) {
		this.secondString = secondString;
	}
	
	@Override
	public String toString() {
		return "First String = "+firstString+", Second String = "+secondString;
	}
}

示例输出:

Enter First String:
Java
Enter Second String:
Python
First String = Java, Second String = Python
First String = Python, Second String = Java

编写一个程序来查找输入字符串中第一个不重复的字符。

package com.Olivia.java.string;

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

public class FindNonRepeatingChar {

	public static void main(String[] args) {

		System.out.println(printFirstNonRepeatingChar("abcaabcdedxy"));
		System.out.println(printFirstNonRepeatingChar("abca"));
		System.out.println(printFirstNonRepeatingChar("aaa"));

	}

	private static Character printFirstNonRepeatingChar(String string) {
		char[] chars = string.toCharArray();

		List<Character> discardedChars = new ArrayList<>();

		for (int i = 0; i < chars.length; i++) {
			char c = chars[i];

			if (discardedChars.contains(c))
				continue;

			for (int j = i + 1; j < chars.length; j++) {
				if (c == chars[j]) { // 找到匹配项
					discardedChars.add(c);
					break;
				} else if (j == chars.length - 1) { // 直到末尾都没有找到匹配项
					return c;
				}
			}
		}
		return null;
	}

}

如何检查字符串是否仅包含数字?提供两种方法。

我们可以使用正则表达式来检查一个字符串是否为数字。另一种方式是将其解析为长整型,如果它是一个非数字字符串,则会抛出NumberFormatException异常。

package com.Olivia.java.string;

public class CheckIfStringContainsDigitsOnly {

	public static void main(String[] args) {
		digitsOnlyString("111");
		digitsOnlyString("111a 1");
		digitsOnlyString("111 222");
		digitsOnlyString("111L");

	}

	private static void digitsOnlyString(String string) {
		if(string.matches("\\d+")) System.out.println("仅包含数字的字符串 ::"+string);
		
		try {
			long l = Long.parseLong(string);
			System.out.println("仅包含数字的字符串 ::"+string);
		}catch(Exception e){
			System.out.println("不包含数字的字符串 ::"+string);
		}
		
	}

}

如何进行字符串的深拷贝?

字符串是不可变的,所以我们不需要担心深拷贝或浅拷贝。我们可以简单地使用赋值操作符(=)将一个字符串复制到另一个字符串。详细信息请阅读Java字符串复制。

你可以从我的GitHub代码库中下载这些示例。

bannerAds