JAVA开发讲义(二)-Java程序设计之数据之谜二
程序之美
重要的事情说三遍,字符串,字符串,字符串,在程序开发中,我们可以说和字符串抬头不见低头见,所以也可以这样说,处理字符串的能力是考验一个程序员是否优秀的一个重要的指标,也是程序员们的基本功。相信很多在校的大学生们,当你们翻看书本时,经常会碰到字符串,字符串解析,字符串数组,字符串排序等,而已经步入工作的小伙伴们,你们可能会碰到的更多,因为你们每天都在处理者字符串拆解与合并的工作,还有一部分正在奔波于找工作途中的小伙伴,我相信你们的感受更深,因为你们每天碰到的面试题目可能根本就离不开字符串。
既然字符串如此重要,我们这一篇的开篇就来介绍字符串,并且配有相应的实例代码,帮助小伙伴们理解与消化,我相信,经过这一篇的讲解,不管时在校的,还是就业的,或者是正在不断面试的朋友们,你们都能有所收获,有所提升。
字符串
JAVA字符串就是Unicode字符序列。例如:“chengxu\u2212”,由8个Unicode字符c、h、e、n、g、x、u和TM。Java没有内置的字符串类型,但却有一个预处理类String。表达如下:
String e = "";//空字符串
String green = "hello green";
String pNULL = null;//未赋值时会出现null空指针
子串
字串只可意会,不可言传,简单来说就是一个字符串的一部分,比方说一个字符串S,那么S的子串为S中任意连续的一段,所以一个字符串最大的字串就是它自己本身,而最小的字符串就是它其中的每一个字符,但这时字符就要作为字符串使用了,比如“good”最小的字串分别为“g”、“o”、“o”、“d”,虽然只有一个字符,但也是子串,也就是字符串中最小的子串。
很多java 的试题和答疑中,字符串的字串考的最多,比如,求一个字符串的全部子串如下:
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class StringSplit {
private static Set<String> aa = new HashSet<String>();//存贮结果
public static void main(String[] args) {
String a = "abcdefgh";
new StringSplit().split(a);
Iterator<String> iterator = aa.iterator();
while (iterator.hasNext()) {
String type = (String) iterator.next();
System.out.println(type);
}
}
public List<String> split(String a){
String sub1 = "1";
String sub2 = "2";
if (a.length()==1) {
//字符串长度为1不须要在进行切割
aa.add(a);//输入长度惟一时直接添加进set
}else{
for(int i =1;i<a.length();i++){
sub1 = a.substring(i);
sub2 = a.substring(0,i);
aa.add(sub1);
aa.add(sub2);
split(sub1);//切割的两个字符串进行递归
split(sub2);//同上
}
}
return null;
}
}
字符串的截取也会经常用到,比如解析网络协议或者解析时间等,都会用到字符串的截取,但这里的截取是有规律的截取,比如定好协议以空格或-间隔,然后进行传输和截取,如下为时间的年月日时分截取:
import java.util.ArrayList;
public class Q {
public static void main(String[] args) {
String str="2019-07-20-11-54"; //初始字符串
ArrayList<String> list = new ArrayList<String>();
String[] st=new String[100];
int num=0;
String temp=null;
while(str!=null) { //解析每一行里面每一块的数据含义
num=str.indexOf('-'); //根据字符串里面分隔的字符来选择 返回的是字符串中第一个该字符出现的位置 (例如.csv文件分隔符就是逗号)
if(num>=0) {
temp=str.substring(0,num); //截取出来的子串存到temp
list.add(temp); //先将子串放到list里面
str=str.substring(num+1); //再将剩下的字符串处理
}
else { //因为处理完最后一个分隔符后就找不到了 所以最后一个就是最后一个子串
list.add(str);
break;
}
}
for(int i=0;i<list.size();++i) {
st[i]=list.get(i); //再将子串放到数组中
}
for(int i=0;i<list.size();++i) {
System.out.println("st["+i+"]="+st[i]);
}
}
}
当然,还有很多用到字符串子串的地方,这里就不一一介绍了,后面用到的地方,我们在针对性的详细介绍。
拼接
字符串的拼接,在Java中也是一个重点,比如进行网络请求是我们经常会用到字符串拼接,如:
String ip = "192.168.1.1";
int port = 8088;
String url = "http://" + ip + ":" + port + "/upload";
这就是一个简单的网络拼接,主要用于进行Http请求时用到,比如一个接口函数,让我们传入IP和Port作为参数,然后进行网络请求,字符串拼接就显得非常有意义了。上面的我们可以完善下:
private boolean is_IP(String IP) {
String str[] = IP.split("\\.");
if (str.length != 4) {
System.out.println("length = " + str.length);
return false;
}
for (int i = 0; i < 4; i++) {
if (str[i].length() > 3) {
return false;
}
for (int j = 0; j < str[i].length(); j++) {
if (!Character.isDigit(str[i].charAt(j))) {
return false;
}
}
for (int j = 0; j < str[i].length(); j++) {
if (Integer.parseInt(str[i]) > 255) {
return false;
}
}
}
return true;
}
public void uploadImage(String ip, int port){
if(!is_IP(ip) || port <= 0){
return;
}
String url = "http://" + ip + ":" + port + "/upload";
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.build();
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
以上代码就是一段简单的网路请求,我们加入了合法性IP检查和端口判断,然后拼接成需要的url进行http请求,这里我们用了OkHttpClient,后面我们会详细阐述,这里就此带过。
不可变字符串
字符串的分类,字符串分为可变的字符串和不可变的字符串两种;这里的不可变与可变指的是字符串的对象还是不是同一个,会不会因为字符串对象内容的改变而创建新的对象。
不可变的字符串:当字符串对象创建完毕之后,该对象的内容(上述的字符序列)是不能改变的,一旦内容改变就会创建一个新的字符串对象;Java中的String类的对象就是不可变的。
可变的字符串:StringBuilder类和StringBuffer类的对象就是可变的;当对象创建完毕之后,该对象的内容发生改变时不会创建新的对象,也就是说对象的内容可以发生改变,当对象的内容发生改变时,对象保持不变,还是同一个。
比如说:
String str = "adbcdefg";
这个字符串就是不可变字符串,因为如果我们这样操作:
String str = "abcdefg";
str = str + "12345";
这时字符串就变为了"abcdefg12345",内存发生了变化,就相当于创建了一个新的字符串对象,故而为不可变字符串。
StringBuilder类和StringBuffer类为可变字符串,因为其内容发生改变后不会创建新的对象,后面我们会详细讲这两个函数,这里不再过多阐述。
检测字符串相等
检测字符串的相等,很多小伙伴可能想到了“=”号,比如“123” == “123”,其实不然,在java中,字符串的比较是不能用“”的,为什么呢。因为: 比较的是双方的地址,而不会比较内容;那么如果要进行字符传比较应该怎么比呢?可以使用compareTo函数和equals函数。
- compareTo: 比较的是双方的内容,而不会比较地址;
- equals: 进行的是字符串的对象的比较。
实例如下:
public class StringCompare {
public static void main(String args[]) {
String s = "a";
String t = "a";
String x = "b";
System.out.println(s.equals(t)); // true
System.out.println(s.compareTo(t)); // 0
System.out.println(s==t); // true ,
System.out.println(s.equals(x)); // false
System.out.println(s.compareTo(x)); // -1
System.out.println(s==x); // false ,
String str = new String("s");
String str2 = new String("s");
System.out.println(str.equals(str2)); // true
System.out.println(str.compareTo(str2)); // 0
System.out.println(str==str2); //false
}
}
空串和NULL串
空串和NULL串,是我们经常会碰到的,我们经常会听到有人说“空指针”、“空指针”啥的,就是NULL串,也就是我们定义一个字符串变量,而没有给它赋任何值:
String str;
System.out.println(str);
此时就为空指针。
而空串和NULL串有着本质的区别,他已经有了内存空间,只是空间中什么都没有而已,如下:
String str = "";
这就是一个空串,已经分配了内存空间,只是没有赋予任何值罢了。
码点和代码单元
码点( code point) 是指与一个编码表中的某个字符对应的代码值。在 Unicode 标准中,码点采用十六进制书写,并加上前缀 U+, 例如 U+0041,码点分成 17 个代码级别( codeplane)。 第一个代码级别码点从 U+0000 到 U+FFFF, 其中包括经典的 Unicode 代码;其余的 16个级别码点从 U+10000 到 U+10FFFF , 还包括一些辅助字符(supplementary character)。
UTF-16 编码采用不同长度的编码表示所有 Unicode 码点。在基本的多语言级别中,每个字符用 16 位表示,通常被称为代码单元( code unit),而辅助字符采用一对连续的代码单元进行编码。为了我们可以从中迅速地知道一个代码单元是一个字符的编码,还是一个辅助字符的第一或第二部分,替代区域(surrogate area) 中 U+D800 ~ U+DBFF 用于第一个代码单元,U+DC00 ~ U+DFFF 用于第二个代码单元 。
String API函数
对于String类型API,真时丰富又完善,小伙伴们可以很方便的进行字符串的各种操作,下面我们简单说几个函数,其他的用到再说。
String 类的一个访问器方法是 length() 方法,它返回字符串对象包含的字符数。实例如下:
public class StringDemo {
public static void main(String args[]) {
String site = "aaabbbcccdd";
int len = site.length();
System.out.println( "当前字符串的长度 : " + len );
}
}
String 类提供了连接两个字符串的方法:
string1.concat(string2);
返回 string2 连接 string1 的新字符串。字符串常量使用 concat() 方法,实例如下:
"白日依山尽 ".concat("是个好诗");
其实它等同于两个字符串相加:
"白日依山尽 " + "是个好诗";
String 类使用静态方法 format() 返回一个String 对象而不是 PrintStream 对象。
String 类的静态方法 format() 能用来创建可复用的格式化字符串,而不仅仅是用于一次打印输出。
实例如下:
String fs;
fs = String.format("浮点型变量的值为 " +
"%f, 整型变量的值为 " +
" %d, 字符串变量的值为 " +
" %s", floatVar, intVar, stringVar);
当然字符串还有很多函数,如:
char charAt(int index)
返回给定位置的代码单元,这个函数过于底层,进过断点调试,你可以看到底层代码的实现过程。
int codePointAt(int index) 5.0
返回从给定位置开始的码点。
int offsestByCodePoints(int startIndex, int cpCount) 5.0
返回从startIndex代码点开始,位移cpCount后的码点索引。
int compareTo(String other)
按照字典顺序,如果字符串位于Other之前,返回一个负数;如果字符串位于other之后,返回一个正数;如果两个字符串相等,返回0。
IntStream codePoints() 8
将这个字符串的码点作为一个流返回,调用toArray将它们放在一个数组中。
new String(int[] codePoints, int offset, int count) 5.0
用数组中从offset开始的count个码点构造一个字符串。
boolean equals(Object other)
如果字符串与Other相等,返回true。
boolean equalsIgnoreCase(String other)
如果字符串与Other相等(忽略大小写),返回true。
boolean startsWith(String prefix)
boolean endsWith(String suffix)
如果字符串以prefix开头或者以suffix结尾,则返回true。
int indexOf(String str)
int indexOf(String str, int fromIndex)
int indexOf(int cp)
int indexOf(int cp, int fromIndex)
返回与字符串str或代码点cp匹配的第一个子串的开始位置。这个位置从索引0或fromIndex开始计算。如果在原始串中不存在str,返回-1。
int lastIndexOf(String str)
int lastIndexOf(String str, int fromIndex)
int lastIndexOf(int cp)
int lastIndexOf(int cp, int fromIndex)
返回与字符串str或代码点cp匹配的最后一个子串的开始位置。这个位置从原始串尾端或fromIndex开始计算。
int length()
返回字符串的长度。
int codePointCount(int startIndex, int endIndex) 5.0
返回startIndex和endIndex-1之间的代码点数量。没有配成对的代用字符将计入代码点。
String replace(CharSequence oldString, CharSequence newString)
返回一个新字符串。这个字符串用newString代替原始字符串中所有的oldString。可以用String或StringBuilder对象作为Charsequence参数。
String substring(int beginIndex)
String subString(int beginIndex, int endIndex)
返回一个新的字符串。这个字符串包含原始字符串中从beginIndex到串尾或endIndex-1的所有代码单元。
String toLowerCase()
String toUpperCase()
返回一个新的字符串。这个字符串将原始字符串中的大写字母改为小写字母,或者将原始字符串中的小写字母改成大写字母。
String trim()
返回一个新字符串。这个字符串将删除了原始字符串头部和尾部的空格。
String join(CharSequence delimiter, CharSequence... elements) 8
返回一个新字符串。用给定的定界符连接所有元素。
另外,还有很多新增的API这就不一一列举了,后面用到的时候,我们在进行详细叙述,进行讲解,有兴趣的小伙伴可以自行学习下。
好了,今天就先讲这么多,因为字符串是我们进行程序开发的重头戏,所有我们专门用一篇来着重介绍,由于个人能力问题,有些地方可能讲的不太全面,欢迎各位小伙伴批评指正,多和我进行交流,非常感谢朋友们能在百忙之中浏览这篇文章。收尾之时,重要的事情说三遍,字符串,字符串,字符串,不要嫌我啰嗦,真的很重要。