一、正则表达式

1、概念

正则表达式:专门用于操作字符串的技术,并且可以简化代码,用于对字符串的复杂操作。 正则表达式弊端:代码可读性比较差。

2、正则表达式常用符号

字符类

语法示例[ ]表示范围的意思。表示某一位上可以出现的字符数据,如果正则中需要匹配的某个字符串中某一位上的字符是唯一的,这时可以省略中括号
1.[abc] 表示要么是a要么是b还可以是c(只能是其中任意一个)
例:”NBA” 正则:”N[ABC]A” 匹配正确:NBA NAA NCA
2.[^abc] 当前要匹配的某个字符串中的某一位上不能是a 或b 或c(除了a,b,c都可以)
3.[a-z] 表示26个小写字母中的任意一个
4.[A-Z] 表示26个大写字母中的任意一个
5.[a-zA-Z] 表示26个大小写字母中的任意一个
6.[a-d[m-p]] 当前要匹配的某个字符串中的某一位上 可以是a - d 或 m - p 的字符
7.[a-d&&[d-f]] 表示只能是d。必须在两个范围中都要符合 。(交集)
8.[a-d&&[^d-f]] 表示只能是a,b,c
9.[a-z&&[^xyz]] 表示只能是除去x,y,z后的所有小写字母
10.[0-9] 表示0~9之间任意数字
11.[a-zA-Z0-9] 表示a-z或者A-Z或者0-9之间的任意一个字符。

逻辑运算符

语法示例1. &&:并且 上面已经演示过
2. | :或者 举例:[a|b|c]:a或b或c 和[abc]效果是一样的

预定义字符

语法示例1. “.” :点 表示当前需要匹配的字符串位置上可以是任意的字符。例:“a.” 以a开始后面可以是任意一个字符
2. “\d”:表示数字[0-9]
3. “\D”:表示非数字[^0-9] 了解
4. “\w”:单词字符:[a-zA-Z_0-9]的简写
5. “\W”:表示[^a-zA-Z_0-9]表示和\w相反。了解

  1. public void show2() {
  2. String s = "0";
  3. //可以匹配一个任何字符
  4. // boolean b = s.matches(".");// String s = "a";
  5. // System.out.println("b = " + b);// true
  6. //可以匹配一个数字
  7. boolean b1 = s.matches("\\d"); //String s = "0";
  8. System.out.println("b1 = " + b1);//true
  9. }

数量词

注意:数量词前面必须有存在正则符号。 语法示例? : 表示0次或1次
* : 表示任意次
+ : 表示1次或多次
{n} : 必须出现n次
{n,} : 至少出现n次
{n,m}: 可以出现n到m次

边界词

语法示例: //1.定义字符串
String str = “12345”;
// 在正则中 ^ 表示以什么开始 $ 表示以什么结尾
String regex = “^[1-9]\d{4,14}$”;
System.out.println(str.matches(regex));

3、正则的功能

正则表达式的主要功能是用来对字符串进行操作:匹配(验证)、切割、替换、获取。 正则表达式需要和String类中的某些函数结合使用。

切割

public String[] split(String regex)//参数regex就是一个正则表达式。可以将当前字符串中匹配regex正则表达式的符号作为"分隔符"来切割字符串。

正则中组的概念:
组:把已经存在的一个正则规则使用小括号封装起来,当在正则表达式中的其他位置上需要使用已经存在的正则规则的时候,这时没有必要再书写重复的规则,而直接去引用被封装好的正则规则。

在正则中一旦把某个规则使用小括号封装成组之后,由于我们只能使用小括号进行组的封装,而无法给组起名, 这时会自动的给这些组进行编号,组的编号从1开始,一个小括号就是一组。 如果在当前分组的这个正则表达式中引用已经存在的组,需要使用 \组的编号

(.) 表示第一组可以是任意字符 \1 表示使用第一组

  • 表示\1的内容至少出现一次
需求1:验证字符串 “哈哈哈”

需求2:验证字符串"哼哈哈哼"

    @Test
    public void show6() {
//        String s = "哈哈哈";
//        //第一对儿()表示第一组,\\1表示再出现一次第一组的内容,{2}表示前面的内容\\1 出现2次
//        boolean b = s.matches("(.)\\1{2}");    //String s = "哈哈哈";
//        System.out.println("b = " + b);//true

        String s = "哼哈哈哼";
        //(.)表示第一组是任意字符  (.)表示第二组是任意字符  \\2表示第二组再出现一次  \\1表示第一组再出现一次
        //一个组里面可以是任意字符
        boolean b = s.matches("(.)(.)\\2\\1");
        System.out.println("b = " + b);//true
    }

替换

String类的replaceAll()方法原型:
public String replaceAll(String regex,String newStr)//参数regex就是一个正则表达式。可以将当前字符串中匹配regex正则表达式的字符串替换为newStr。

二、Collection集合

1、集合概述

集合:集合是java中提供的一种容器,可以用来存储多个数据。

问题:集合和数组既然都是容器,它们有什么区别呢?

数组的长度是固定的。集合的长度是可变的。数组中存储的是同一类型的元素,可以定义任意类型的数组存储任意类型数据。集合存储的都是引用数据类型。如果想存储基本类型数据需要存储对应的包装类型。
存储整数:int[] 存储字符串:String[]
存储整数:ArrayList 存储字符串:ArrayList

2、集合常用类的继承体系

Collection:单列集合类的根接口,用于存储一系列符合某种规则的元素,它有两个重要的子接口,分别是java.util.List和java.util.Set。其中,List的特点是元素存取有序、元素可重复 ; Set的特点是元素存取无序,元素不可重复。List接口的主要实现类有java.util.ArrayList和java.util.LinkedList,Set接口的主要实现类有java.util.HashSet和java.util.LinkedHashSet。集成体系图如下 image.png

Collection 常用功能

  • public boolean add(E e): 把给定的对象添加到当前集合中 。
  • public void clear() :清空集合中所有的元素。
  • public boolean remove(E e): 把给定的对象在当前集合中删除。
  • public boolean contains(Object obj): 判断当前集合中是否包含给定的对象。
  • public boolean isEmpty(): 判断当前集合是否为空。
  • public int size(): 返回集合中元素的个数。
  • public Object[] toArray(): 把集合中的元素,存储到数组中

三、Iterator迭代器

1、 Iterator接口

迭代的概念:

迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就再取出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。

注意:调用next()方法获取数据之前一定先调用hasNext()方法判断有没有有数据,否则会报异常。

方法 说明
public Iterator iterator() 获取集合对应的迭代器,用来遍历集合中的元素的。

Iterator接口的常用方法

方法 说明
E next() 获取集合中的元素
boolean hasNext() 判断集合中有没有下一个元素,如果仍有元素可以迭代,则返回 true。
void remove() 删除当前元素

问题:迭代中为什么会出现NoSuchElementException异常?

原因: 当迭代器对象指向集合时,可以获取集合中的元素,如果迭代器的光标移动集合的外边时,此时迭代器对象不再指向集合中的任何元素,会报NoSuchElementException没有这个元素异常。 解决方案: 在使用next()函数获取集合中元素前,使用hasNext()判断集合中是否还有元素。

迭代器的实现原理

当遍历集合时,首先通过调用集合的iterator()方法获得迭代器对象,然后使用hashNext()方法判断集合中是否存在下一个元素,如果存在,则调用next()方法将元素取出,否则说明已到达了集合末尾,停止遍历元素。Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素。在调用Iterator的next方法之前,迭代器的索引位于第一个元素之前,不指向任何元素,当第一次调用迭代器的next方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next方法时,迭代器的索引会指向第二个元素并将该元素返回,依此类推,直到hasNext方法返回false,表示到达了集合的末尾,终止对元素的遍历。

public class ArrayList<E>{
    //Itr属于ArrayList集合的成员内部类,实现了迭代器Iterator接口
    private class Itr implements Iterator<E> {
        //定义游标,默认值是0
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        /*
            1.第一个 modCount 集合结构变动次数,如:一开始add调用了4次,那么这个变量就是4
            2.第二个 expectedModCount表示期望的更改次数 在调用iterator()方法时,初始化值等于modCount ,初始化时也是4,这里 int expectedModCount = modCount;
        */
        int expectedModCount = modCount;
        //判断集合是否有数据的方法,如果有数据返回true,没有返回false
        //size表示集合长度,假设添加3个数据,那么size的值就是3
        public boolean hasNext() {
            /*
                判断游标变量cursor是否等于集合长度size,假设向集合中存储三个数据那么size等于3
                1.第一次cursor的默认值是0 size是3 --》cursor != size --》0!=3-->返回true
            */
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            //主要作用是判断it迭代器数据是否和list集合一致 我们下面会讲解
            checkForComodification();
            //每次调用一次next方法都会将游标cursor的值赋值给变量i
            int i = cursor;
            //判断i是否大于等于集合长度size,如果大于等于则报NoSuchElementException没有这个元素异常
            if (i >= size)
            throw new NoSuchElementException();
            //获取ArrayList集合的数组
            Object[] elementData = ArrayList.this.elementData;
            //判断i的值是否大于等于数组长度,如果为true则报并发修改异常
            if (i >= elementData.length)
            throw new ConcurrentModificationException();
            /*
                将i的值加1赋值给游标cursor.就是将游标向下移动一个索引,可以理解指针向下移动一次
            */
            cursor = i + 1;
            /*
                elementData就是集合的底层数组,获取索引i位置的元素返回给调用者
            */
            return (E) elementData[lastRet = i];
        }
      }
}

image.png

迭代器的问题:并发修改异常

ConcurrentModificationException(并发修改异常) 产生原因:

  • 在迭代器遍历的同时如果使用集合对象修改集合长度(增或删)就会出现并发修改异常。
package com.itheima.sh.demo_04;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Test01 {
    public static void main(String[] args) {
        Collection<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("ddd");
        list.add("bbb");
        list.add("ccc");
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String s = it.next();
            if("ddd".equals(s)){
                //使用集合调用方法删除
                list.remove(s);
            }
        }
        System.out.println(list);
    }
}

解决办法:

  • 使用集合增加或删除都会出现并发修改异常。
  • 在Iterator迭代器中,有删除方法可以避免异常。但是他没有增加的方法。
  • 使用迭代器方法remove删除即可

增强for

增强for循环(也称for each循环)是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。

for(元素的数据类型  变量 : Collection集合or数组){ 
      //写操作代码
}
它用于遍历Collection和数组。通常只进行遍历元素,不要在遍历的过程中对集合元素进行增删操作。

提示:
1.快捷键:
1)数组/集合.for
2)iter
2.增强for循环必须有被遍历的目标,目标只能是Collection或者是数组;
3.增强for(迭代器)仅仅作为遍历操作出现,不能对集合进行增删元素操作,否则抛出ConcurrentModificationException并发修改异常
4.如果需要使用索引,也不能使用增强for

小结:Collection是所有单列集合的根接口,如果要对单列集合进行遍历,通用的遍历方式是迭代器遍历或增强for遍历。