【JavaSE复习】数据结构、集合

JavaSE 复习

  • 1.数据结构
    • 1.1 查找
      • 1.1.1 基本查找
      • 1.1.2 二分查找
      • 1.1.3 插值查找
      • 1.1.4 斐波那契查找
      • 1.1.5 分块查找
      • 1.1.6 分块查找的扩展(无规律数据)
    • 1.2 排序
      • 1.2.1 冒泡排序
      • 1.2.2 选择排序
      • 1.2.3 插入排序
      • 1.2.4 快速排序
  • 2. 集合
    • 2.1 基础集合
      • 2.1.1 集合和数组的对比
      • 2.1.2 ArrayList
    • 2.2 单列集合
      • 2.2.1 Collection单列集合
        • 2.2.1.1 Collection的遍历方式一:迭代器遍历
        • 2.2.1.2 Collection的遍历方式二:增强for遍历
        • 2.2.1.3 Collection的遍历方式三:Lambda表达式遍历
      • 2.2.2 List集合
        • 2.2.2.1 迭代器遍历
        • 2.2.2.2 增强for遍历方式
        • 2.2.2.3 Lambda表达式方式
        • 2.2.2.4 普通for循环
        • 2.2.2.5 列表迭代器
        • 2.2.2.6 五种遍历方式对比
      • 2.2.3 ArrayList集合
      • 2.2.4 LinkedList集合
      • 2.2.5 泛型深入
        • 2.2.5.1 泛型类
        • 2.2.5.2 泛型方法
        • 2.2.5.3 泛型接口
      • 2.2.6 Set集合
      • 2.2.6 HashSet集合
      • 2.2.7 HashSet集合
      • 2.2.8 TreeSet集合
    • 2.3 双列集合
      • 2.3.1 Map集合
        • 2.3.1.1 Map集合常用的API
        • 2.3.1.2 遍历方式一:键找值
        • 2.3.1.3 遍历方式二:键值对
        • 2.3.1.4 遍历方式三:Lambda表达式
      • 2.3.2 HashMap集合
      • 2.3.3 LinkedHashMap
      • 2.3.4 TreeMap
      • 2.3.5 集合工具类Collections
  • 3 Stream流和方法引用
    • 3.1 Stream流的思想
      • 3.1.1 得到stram流,把数据放上去
      • 3.1.2 中间方法
      • 3.1.3 终结方法
  • 其他
    • Arrays
    • Lambda表达式

1.数据结构

1.1 查找

1.1.1 基本查找

for 循环直接查找

package searchdemo;

public class SearchDemo1 {
    public static void main(String[] args) {
        //基本查找
        int[] arr = {131,127,147,81,103,23,7,79};
        boolean b = basicSearch(arr, 81);
        System.out.println(b);
    }
    public static boolean basicSearch(int[] arr,int number){
        for (int i = 0; i < arr.length; i++) {
            if(number == arr[i])
                return true;
        }
        return false;
    }
}

1.1.2 二分查找

折半查找,每次改变中间指针的位置,要求原序列有序

public class SearchDemo3 {
    public static void main(String[] args) {
        //折半查找
        //min和max表示当前要查找的范围,mid是在min和max中间.
        int[] arr = {7,23,79,81,103,127,131,147};
        System.out.println(binarySearch(arr,81));
    }
    public static int binarySearch(int[] arr,int number){
        int min = 0;
        int max = arr.length-1;
        while(true){
            if(min > max){
                return -1;
            }
            int mid = (min + max) / 2;
            if(arr[mid] > number){
                max = mid - 1;
            }else if(arr[mid] < number){
                min = mid + 1;
            }else{
                return mid;
            }
        }
    }
}

1.1.3 插值查找

mid = min+ key-arr[min]/arr[max]-arr[min] * (max-min)
在这里插入图片描述

1.1.4 斐波那契查找

根据黄金分割点来计算mid指向的位置

1.1.5 分块查找

原则:

  1. 前一块所有数据小于后一块所有数据(块内无序、块间有序)
  2. 块数的等于总数字个数开根号
  3. 思路:先确定查找的元素在哪一块,然后在块内查找
public class BlockSearch {
    public static void main(String[] args) {
        int[] arr = {16, 5, 9, 12, 21, 18, 32, 23, 37, 26, 45, 34, 50, 48, 61, 52, 73, 66};
        
        // Creating blocks with their maximum values and their start and end indices in the array
        Block b1 = new Block(21, 0, 5);
        Block b2 = new Block(45, 6, 11);
        Block b3 = new Block(73, 12, 17);
        
        Block[] blockArr = {b1, b2, b3};
        
        int number = 32; // The number we are searching for
        
        // Find the block that might contain the number
        int indexBlock = findIndexBlock(blockArr, number);
        
        if (indexBlock == -1) {
            System.out.println(false);
        } else {
            boolean found = false;
            // Linear search within the identified block
            for (int i = blockArr[indexBlock].getStartIndex(); i <= blockArr[indexBlock].getEndIndex(); i++) {
                if (number == arr[i]) {
                    found = true;
                    System.out.println(true);
                    break;
                }
            }
            if (!found) {
                System.out.println(false);
            }
        }
    }
    
    private static int findIndexBlock(Block[] blockArr, int number) {
        for (int i = 0; i < blockArr.length; i++) {
            if (blockArr[i].getMax() >= number) {
                return i;
            }
        }
        return -1;
    }
}

class Block {
    private int max;
    private int startIndex;
    private int endIndex;

    public Block(int max, int startIndex, int endIndex) {
        this.max = max;
        this.startIndex = startIndex;
        this.endIndex = endIndex;
    }

    public int getMax() {
        return max;
    }

    public int getStartIndex() {
        return startIndex;
    }

    public int getEndIndex() {
        return endIndex;
    }

    @Override
    public String toString() {
        return "Block{max = " + max + ", startIndex = " + startIndex + ", endIndex = " + endIndex + "}";
    }
}

1.1.6 分块查找的扩展(无规律数据)

数据本身没有明显的规律,那么定义块的时候将(最大值,起始索引,结束索引)换成(最小值,最大值,起始索引),块的分割需要手动定义

public class BlockSearchDemo2 {
    public static void main(String[] args) {
        int[] arr = {27,22,30,40,36,
                13,19,16,20,
                7,10,
                43,50,48};
        int number = 30;
        BlockSearch2 block1 = new BlockSearch2(22,40,0);
        BlockSearch2 block2 = new BlockSearch2(13,20,5);
        BlockSearch2 block3 = new BlockSearch2(7,10,9);
        BlockSearch2 block4 = new BlockSearch2(43,50,11);
        BlockSearch2[] blockArr = {block1,block2,block3,block4};
        int index = findIndex(blockArr, number);
        if(index == -1) {
            System.out.println(false);
        }else{
            boolean flag = false;
            for (int i = blockArr[index].getIndex(); i < blockArr[index + 1].getIndex(); i++) {
                if(number == arr[i]){
                    flag = true;
                    System.out.println(true);
                    break;
                }
            }
            if(!flag){
                System.out.println(false);
            }
        }
    }
    private static int findIndex(BlockSearch2[] blockArr,int number){
        for (int i = 0; i < blockArr.length; i++) {
            if(number >= blockArr[i].getMin() && number <= blockArr[i].getMax()){
                return i;
            }
        }
        return -1;
    }
}
class BlockSearch2 {
    private int min;
    private int max;
    private int index;


    public BlockSearch2() {
    }

    public BlockSearch2(int min, int max, int index) {
        this.min = min;
        this.max = max;
        this.index = index;
    }

    /**
     * 获取
     * @return min
     */
    public int getMin() {
        return min;
    }

    /**
     * 设置
     * @param min
     */
    public void setMin(int min) {
        this.min = min;
    }

    /**
     * 获取
     * @return max
     */
    public int getMax() {
        return max;
    }

    /**
     * 设置
     * @param max
     */
    public void setMax(int max) {
        this.max = max;
    }

    /**
     * 获取
     * @return index
     */
    public int getIndex() {
        return index;
    }

    /**
     * 设置
     * @param index
     */
    public void setIndex(int index) {
        this.index = index;
    }

    public String toString() {
        return "BlockSearch2{min = " + min + ", max = " + max + ", index = " + index + "}";
    }
}

1.2 排序

1.2.1 冒泡排序

1.相邻元素两两比较,小的放前面,大的放后面
2.一轮循环结束,最大值已经找到,在数组最右
3.第二轮循环在剩余元素中找最大值
4.N个数据,进行N-1轮比较

public class sortdemo1 {
    public static void main(String[] args) {
        int[] arr = {2,4,5,3,1};
        for(int i = 0; i < arr.length - 1;i++){//轮数
            for(int j = 0;j < arr.length - i - 1;j++){//每一轮中如何比较数据并找到当前的最大值
                if(arr[j] > arr[j + 1]){
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

1.2.2 选择排序

从0索引开始,拿着每一个元素跟后面的元素一次比较,小的放前面,大的放后面,以此类推.

public class SortDemo2 {
    public static void main(String[] args) {
        int[] arr = {2,4,5,3,1};
        for (int i = 0; i < arr.length - 1; i++) {//这一轮拿哪个索引跟后面的数据比较
            for (int j = i + 1; j < arr.length; j++) {//每一轮的比较
                if(arr[i] > arr[j]){
                    int temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

1.2.3 插入排序

将0索引到N索引元素看作有序,将N+1索引到最后元素看作无序。遍历无序数据,将遍历到的元素插入适当位置,如果遇到相同数据,插在后面。

public class SortDemo3 {
    public static void main(String[] args) {
        int[] arr = {3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};
        //找到无序的那一组数据是从哪个索引开始的
        int startIndex = -1;
        for(int i = 0;i < arr.length; i++){
            if(arr[i] > arr[i+1]){
                startIndex = i; //有序的最后一个元素
                break;
            }
        }
        //遍历startindex开始到最后一个元素,依次得到无序的那一组每一个元素
        for (int i = startIndex; i < arr.length-1; i++) {
             for(int j = i + 1;j > 0;j--){ //从后往前找位置
                 if(arr[j] < arr[j-1]){
                     int temp = arr[j];
                     arr[j] = arr[j - 1];
                     arr[j - 1] = temp;
                 }else if(arr[j] >= arr[j-1]){
                     break;
                 }
             }
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }
}

1.2.4 快速排序

递归算法
递归指的是方法中调用方法本身的现象
注意: 递归一定要有出口,否则就会出现内存溢出
可以将一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量程序就可以描述出解题过程所需要的多次重复计算.
快速排序
第一轮:把0索引的数组作为基准数,确定基准数在数组中正确的位置,比基准数小的或等于的全部在左边,比基准数大的全部在右边
画图!!!

public class QuickSortDemo {
    public static void main(String[] args) {
        int[] arr = {27, 22, 30, 40, 36, 13, 19, 16, 20, 7, 10, 43, 50, 48};
        System.out.println("Unsorted array:");
        printArray(arr);

        quickSort(arr, 0, arr.length - 1);

        System.out.println("Sorted array:");
        printArray(arr);
    }

    // 快速排序主方法
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            int pi = partition(arr, low, high); // 获取分区索引

            quickSort(arr, low, pi - 1); // 递归排序左子数组
            quickSort(arr, pi + 1, high); // 递归排序右子数组
        }
    }

    // 分区方法
    public static int partition(int[] arr, int low, int high) {
        int pivot = arr[low]; // 选择最左元素为基准
        int i = low + 1; // 从第二个元素开始
        int j = high;

        while (i <= j){  
            // 找到第一个大于基准的元素
            while (i <= j && arr[i] <= pivot) {
                i++;
            }

            // 找到第一个小于基准的元素
            while (i <= j && arr[j] > pivot) {
                j--;
            }

            // 交换 arr[i] 和 arr[j]
            if (i < j) {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }

        // 将基准放到正确的位置
        int temp = arr[low];
        arr[low] = arr[j];
        arr[j] = temp;

        return j; // 返回基准的索引
    }

    // 打印数组方法
    public static void printArray(int[] arr) {
        for (int i : arr) {
            System.out.print(i + " ");
        }
        System.out.println();
    }
}

2. 集合

2.1 基础集合

2.1.1 集合和数组的对比

1.长度:数组长度固定,集合长度可变
2.存储类型:数组:基本数据类型和引用数据类型;集合:引用数据类型,基本数据类型需要借用包装类来存储

2.1.2 ArrayList

1.打印:打印一个对象,默认情况下打印的是对象的类型名加上它的哈希码的十六进制形式,
ArrrayList重写了toString()方法,打印集合中存储的元素内容。
2.泛型: 进一步限定了集合中存储的对象类型,确保类型安全和明确的类型定义。(下面的String)

ArrayList<String> list = new ArrayList<String>();
ArrayList<String> list2 = new ArrayList<>();
ArrayList<Integer> intList = new ArrayList<>();

在这里插入图片描述
3.基本数据类型对应的包装类
byte->Byte
short->Short
char->Character
int->Integer
long->Long
float->Float
double->Double
boolean->Boolean

2.2 单列集合

List系列集合: 元素有序,可重复,有索引,添加元素永远返回值为True
Set系列集合: 元素无序,不可重复,无索引,添加元素已存在返回值为False
在这里插入图片描述

2.2.1 Collection单列集合

Collection 是单列集合的祖宗接口,功能是全部单列集合都可以继承使用
1.不能通过索引删除
2.删除元素不存在返回False
3.判断是否存在时,底层用equals方法实现的,集合存储自定义对象想通过contains方法判断,一定要重写equals方法
在这里插入图片描述

public class CollectionDemo1 {
    public static void main(String[] args) {
        Collection<String> coll= new ArrayList<>();
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        coll.clear();
        coll.remove("ccc");
        coll.contains("aaa");
        boolean result2 = coll.isEmpty();
        int size = coll.size();
    }
}
2.2.1.1 Collection的遍历方式一:迭代器遍历
public class CollectionDemo2 {
    public static void main(String[] args) {
        Collection<String> coll = new ArrayList<>();
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        coll.add("ddd");
        //获取迭代器对象,迭代器对象就好比是一个箭头,指向集合的0索引
        Iterator<String> it = coll.iterator();
        while(it.hasNext()){
            String next = it.next();
            System.out.println(next);
        }
    }
}
2.2.1.2 Collection的遍历方式二:增强for遍历
public class CollectionDemo3 {
    public static void main(String[] args) {
        Collection<String> coll = new ArrayList<>();
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        coll.add("ddd");
        //简写:coll.for+回车
        //注意:S其实就是一个第三方变量,在循环过程中依次表示集合中的每一个数据
        for (String s : coll) {
            System.out.println(s);
        }
    }
}
2.2.1.3 Collection的遍历方式三:Lambda表达式遍历
 coll.forEach(s->System.out.println(s));

2.2.2 List集合

List集合独有的方法
在这里插入图片描述

public class ListDemo1 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        //再次集合中的指定位置插入指定元素
        //细节:原来索引上的元素会依次后移
        list.add(2,"ddd");
        list.remove("ddd");
        list.remove(0);//删除0索引上对应元素,并且将被删除元素作为返回值,其他元素前移
        list.set(0,"qqq");//修改之后会将被修改的元素做一个返回
        String s = list.get(0);
    }
}
2.2.2.1 迭代器遍历
Iterator<String> it = list.iterator();
while(it.hasNext()){
	sout(it.next());
}
2.2.2.2 增强for遍历方式
for(String s : list){
            System.out.println(s);
}
2.2.2.3 Lambda表达式方式
list.forEach(s -> System.out.println(S));
2.2.2.4 普通for循环
for (int i = 0; i < list.size(); i++) {//集合的大小是list.size()
            System.out.println(list.get(i));
        }
2.2.2.5 列表迭代器
//列表迭代器
        //获取列表迭代器的对象,里面的指针默认也是指向0索引的
        //额外添加了一个方法:在便利的过程中,可以添加元素
        ListIterator<String> it2 = list.listIterator();
        while(it2.hasNext()){
            String s = it2.next();
            if(s.equals("bbb")){
                it2.add("eee");
            }
        }
2.2.2.6 五种遍历方式对比

在这里插入图片描述

2.2.3 ArrayList集合

ArrayList集合底层原理
1.利用空参创建的集合,在底层创建一个默认长度为0的数组
2.添加第一个元素时,底层会创建一个新的长度为10的数组
3.存满时,会扩容1.5倍
4.如果一次添加多个元素,1.5倍放不下则新创建数组长度以实际为准

在这里插入图片描述

2.2.4 LinkedList集合

底层数据结构是双链表,查询慢,增删快,但是如果操作的是首尾元素,速度也是极快的
LinkList本身多了很多直接操作首尾元素的特有API
在这里插入图片描述

2.2.5 泛型深入

1.泛型: 是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
2.格式: List
3.限制: 泛型只能支持引用数据类型
4.好处: 如果没有给集合指定类型,Java 默认认为集合中的所有数据类型都是 Object。这样,集合可以存储任意类型的数据。
在运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来。
5.劣势: 在获取数据时,由于数据类型被认为是 Object,无法直接使用其特有的方法和行为,需要进行类型转换。
6.泛型的扩展: Java中的泛型是伪泛型
当集合中想要添加元素时,集合验证数据类型与集合泛型是否符合,若符合加入集合。在集合内的存储中,数据类型为Object,当将数据取出集合后,又将数据类型转换为原来数据类型。
7.泛型的细节:
指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型
如果不写泛型,类型默认是Object

2.2.5.1 泛型类

当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类

public class ArrayList<E>{
//此处E可以理解为变量,但是不是用来记录数据的,而是记录数据的类型,可以写成:T,E,K,V等
}
2.2.5.2 泛型方法

方法中形参类型不确定时,可以使用类名后面定义的泛型
1.使用类名后面定义的泛型-所有方法都能用
2.在方法申明上定义自己的泛型-只有本方法能用

public <T> void show(T t){

}
public static<E> void addAll(ArrayList<E> list,E...e){
// public:方法的访问修饰符,表示该方法可以被任何类调用。
// static:方法是静态的,可以直接通过类名调用,而不需要实例化该类。
// <E>:这是方法的泛型类型参数声明,表示方法是泛型方法。
// ArrayList<E> list:方法的第一个参数,类型为 ArrayList<E>,表示要添加元素的列表。
// E... e:方法的第二个参数,是一个可变参数,类型为 E。可变参数表示可以传入任意数量的 E 类型的参数(包括零个)。
        for (E e1 : e) {
            list.add(e1);
        }
    }
2.2.5.3 泛型接口
public interface List<E>{

}

使用方式
1.实现类给出具体类型
2.实现类延续泛型,创建对象时再确定
泛型的继承和通配符
1.泛型不具备继承性,但数据具备继承性
在泛型中,List 并不是 List 的子类,即使 Dog 是 Animal 的子类。
这意味着你不能将 List 赋值给 List。可以将 Dog 类型的数据放入 Animal 类型的容器中(例如 ArrayList)

2.2.6 Set集合

HashSet: 无序,不重复,无索引
LinkedHashSet: 有序,不重复,无索引
TreeSet: 可排序,不重复,无索引
Set接口中的方法上基本上与Collection的API一致

public class SetDemo1 {
    public static void main(String[] args) {
        Set<String> s= new HashSet<>();
        boolean r1 = s.add("张三");
        boolean r2 = s.add("lisi");
        boolean r3 = s.add("wangwu");
        //迭代器的方法遍历
        Iterator<String> it = s.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        //Lamdba表达式方法
        s.forEach(i-> System.out.println(i));
    }
}

2.2.6 HashSet集合

HashSet底层原理
HashSet集合底层采取哈希表 存储数据
哈希值
1.哈希值根据HashCode方法算出来的int类型的整数
2.该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算
3.一般情况下,会重写HashCode方法,利用对象内部的属性值计算哈希值
对象的哈希值特点
1.如果没有重写HashCode方法,不同对象 计算出的哈希值是不同的
2.如果已经重写HashCode方法,不同的对象只要属性值 相同,计算出的哈希值就是一样的
3.在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样(哈希碰撞
HashSet底层原理
1.创建一个默认长度为16,默认加载因子为0.75的数组,数组名为table
2.根据元素的哈希值跟数组长度计算出应存入的位置
3.判断当前位置是否为null,如果是null直接存入
4.如果位置不为null,表示有元素,则调用equals方法比较属性值
5.一样:不存 不一样:存入数组,形成链表
JDK8以前:新元素存入数组,老元素挂在新元素下面
JDK8以后:新元素直接挂在老元素下面

2.2.7 HashSet集合

有序,不重复,无索引
原理: 底层数据结构是依然哈希表,只是每个元素又额外的多了一个双链表的机制记录存储顺序

2.2.8 TreeSet集合

无重复,无索引,可排序
可排序:按照元素的默认规则(有小有大)排序
TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好
TreeSet集合默认的规则
1.对于数值类型:Integer,Double,默认按照从小到大的顺序进行排序
2.对于字符,字符串:按照字符在ASCII码表中的数字升序进行排序a->b->c->…
TreeSet的两种比较方式
方式一:默认排序/自然排序: Javabean实现Comparable接口指定比较规则
方式二:比较器排序 创建TreeSet对象的时候,传递比较器Comparator制定规则
使用原则:默认使用第一种,如果第一种不能满足条件,再使用第二种
在这里插入图片描述

2.3 双列集合

特点:
1.单列集合每次添加一个元素,双列集合每次添加一对元素(键——不可重复,值——可以重复)
2.一对键和值称为键值对对象、键值对、Entry对象
在这里插入图片描述

2.3.1 Map集合

2.3.1.1 Map集合常用的API

1.Map是双列集合的顶层接口,它的功能是全部双列集合都可以继承使用的
在这里插入图片描述
2.put方法的细节:添加、覆盖
在添加数据时,如果键不存在,那么直接把键值对对象添加到map集合当中,方法返回null。
在添加数据时,如果键存在,那么会把原有的键值对对象覆盖,会把覆盖的原值进行返回。
3.remove方法的细节
在删除数据时,如果键存在,那么把键值对对象删除,返回被删除对象的值
在删除数据时,如果键不存在,返回null

2.3.1.2 遍历方式一:键找值

键不能重复,所以用set
1)将双列集合中的键统一提取出来,存入一个单列集合。
map.KeySet();返回值为双列集合的所有键,直接存入单列set集合
2)在单列集合中通过get方法获得对应的值
map.get(Key);通过键值找到双列集合中对应的值

public class A02_MapDemo2 {
    public static void main(String[] args) {
        //Map集合的第一种遍历方式
        //创建Map对象
        Map<String,String> m = new HashMap<>();

        //添加元素
        m.put("a","b");
        m.put("c","d");
        m.put("e","f");

        //获取所有键,将键存入一个 单列集合当中
        Set<String> keys = m.keySet();
        //遍历单列集合,得到每一个键
        for (String key : keys) {
            String value = m.get(key);
            System.out.println(key + "=" + value);
        }
    }
}
2.3.1.3 遍历方式二:键值对

1)获取双列集合中的所有键值对
map.entrySet();返回值为键值对对象entry的单列set集合,set集合里面的对象为entry对象
2)分别获取每一个键值对中的键和值
entry.getKey();
entry.getValue();

public class A03_MapDemo3 {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("a","b");
        map.put("c","d");
        map.put("e","f");
        
        //通过键值对对象进行遍历
        Set<Map.Entry<String, String>> entries = map.entrySet();//set里面是entry对象,entry里面装键和值
        //由于entry是map接口里面的内部接口,所以需要外部接口.调用即Map.Entry

        //遍历entries集合
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key);
            System.out.println(value);
        }
    }
}
2.3.1.4 遍历方式三:Lambda表达式
public class A04_MapDemo4 {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();
        map.put("a","b");
        map.put("c","d");
        map.put("e","f");

        //匿名内部类遍历
        map.forEach(new BiConsumer<String, String>() {
            @Override
            public void accept(String key, String value) {
                System.out.println(key + " " + value);
            }
        });
        //lambda表达式遍历
        map.forEach((String key, String value)-> {
                System.out.println(key + " " + value);
            }
        );
        map.forEach((key,value)->System.out.println(key + " " + value));
    }
}

2.3.2 HashMap集合

在这里插入图片描述

2.3.3 LinkedHashMap

1)由键决定:有序、无重复、无索引
2)这里的有序指的是保证存储和取出元素的顺序一致
3)原理:底层数据元素依然是哈希表,只是每个键值对元素又额外多了一个双链表的机制记录存储的顺序。
在这里插入图片描述

2.3.4 TreeMap

1)TreeMap和TreeSet底层原理一样,都是红黑树结构的
2)由键决定特性:不重要、无索引、可排序
3)可排序:对键进行排序
4)注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则
代码书写两种规则

1)实现Comparable接口,指定比较规则
2)创建 集合时传递Comparator比较器对象,指定比较规则(二者都存在,以2为准)

2.3.5 集合工具类Collections

1)java.util.Collections:是集合工具类
2)作用:Collection不是集合,而是集合的工具类
在这里插入图片描述

public class CollectionsDemo1 {
    public static void main(String[] args) {
        //1.创建集合对象
        ArrayList<String> list = new ArrayList<>();

        //2.批量添加
        Collections.addAll(list,"abc","aa","bb","cc");
        System.out.println(list);
        
        //3.打乱shuffle
        Collections.shuffle(list);
        System.out.println(list);
    }
}

3 Stream流和方法引用

3.1 Stream流的思想

作用
结合了Lambda表达式,简化集合、数组的操作
使用步骤
1.得到stram流,把数据放上去
2.利用stream中的API进行各种操作
分类
1.中间方法:过滤、转换
2.终结方法:统计、打印

3.1.1 得到stram流,把数据放上去

1.单列集合


public class StreamDemo2 {
    public static void main(String[] args) {
        //1.单列集合获取Stream流
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a","b","c","d","e");
        //获取到一条流水线,并把集合中的数据放到流水线上
        Stream<String> stream1 = list.stream();
        //使用终结方法打印流水线上的数据
        stream1.forEach(name-> System.out.println(name));
        //list.stream().forEach(name-> System.out.println(name));
    }
}

2.双列集合

public class SreamDemo3 {
    public static void main(String[] args) {
        //1.创建双列集合
        HashMap<String,Integer> hm = new HashMap<>();
        //2.添加数据
        hm.put("aaa",111);
        hm.put("bbb",222);
        hm.put("ccc",333);
        hm.put("ddd",444);
        //3.获取stream流
        hm.keySet().stream().forEach(s -> System.out.println(s));
        hm.entrySet().stream().forEach(s -> System.out.println(s));
    }
}

3.数组

public class StreamDemo4 {
    public static void main(String[] args) {
        //1.创建数组
        int[] arr = {1,2,3,4,5,6,7,8,9,10};
        String[] arr2 = {"a","b","c"};
        //2.获取Stream流
        Arrays.stream(arr).forEach(s-> System.out.println(s));
        Arrays.stream(arr2).forEach(s-> System.out.println(s));
    }
}

4.其他零散数据

public class StreamDemo5 {
    public static void main(String[] args) {
        //一堆零散数据,要求数据的种类相同
        Stream.of(1,2,3,4,5).forEach(s-> System.out.println(s));
        Stream.of("a","b","c","d","e").forEach(s-> System.out.println(s));
    }
}

注意
1)方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
2)但是数组必须是引用数据类型,如果传递基本数据类型,是会把整个数组当作一个元素,放到Stream当中。

3.1.2 中间方法

在这里插入图片描述
1)中间方法返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
2)修改Stream流中的数据,不会影响原来集合或者数组中的数据

//filter 过滤,把开头的留下,其余的数据不要
list.stream().filter(s->s.startsWith("张")).forEach(s-> System.out.println(s));

//limit获取前几个元素
        list.stream().
                limit(3).
                forEach(s-> System.out.println(s));

//skip跳过前几个元素
        list.stream().
                skip(3).
                forEach(s-> System.out.println(s));

 //distinct 元素去重,依赖(hashCode和equals方法)
        list1.stream().distinct().forEach(s-> System.out.println(s));

//concat 合并a和b两个流为一个流
     Stream.concat(list1.stream(),list2.stream()).forEach(s-> System.out.println(s));
 list.stream().
                map(s->Integer.parseInt(s.split("-")[1])).
                forEach(s-> System.out.println(s));

3.1.3 终结方法

在这里插入图片描述

list.stream().forEach(s-> System.out.println(s));
long count = list.stream().count();
        System.out.println(count);
String[] arr2 = list.stream().toArray(value -> new String[value]);
        

其他

Arrays

操作数组的工具类
在这里插入图片描述

import java.util.Arrays;

public class ToStringDemo {
    public static void main(String[] args) {
        int[] intArray = {1, 2, 3, 4, 5};
        System.out.println(Arrays.toString(intArray)); // 输出: [1, 2, 3, 4, 5]

        String[] stringArray = {"Hello", "World", "Java"};
        System.out.println(Arrays.toString(stringArray)); // 输出: [Hello, World, Java]

        char[] charArray = {'a', 'b', 'c', 'd'};
        System.out.println(Arrays.toString(charArray)); // 输出: [a, b, c, d]

        double[] doubleArray = {1.1, 2.2, 3.3, 4.4};
        System.out.println(Arrays.toString(doubleArray)); // 输出: [1.1, 2.2, 3.3, 4.4]
    }
}

Lambda表达式

函数式编程
面向对象先找对象,让对象做事情

Arrays.sort(arr,new Comparator<Integer>(){
	public int compare(Integer o1,Integer o2){
		return o1 - o2;
	}
});

函数式编程忽略面向对象的复杂语法,强调做什么,而不是谁去做
Lambda表达式就是函数式思想的体现
格式

() -> {
}

1.() 对应着方法的形参
2.-> 固定格式
3.{} 对应方法的方法体

Arrays.sort(arr,(Integer o1,Integer o2)->{
		return o1 - o2;
});

注意:
1.Lambda表达式可以用来简化匿名内部类的书写
2.Lambda表达式只能简化函数式接口 的匿名内部类的写法
3.函数式接口 :有且只有一个抽象方法的接口叫做函数式接口,接口上方可以加@FunctionalInterface注解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/781259.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis中二级缓存的配置与实现原理

大家好&#xff0c;我是王有志&#xff0c;一个分享硬核 Java 技术的金融摸鱼侠&#xff0c;欢迎大家加入 Java 人自己的交流群“共同富裕的 Java 人”。 上一篇文章《MyBatis中一级缓存的配置与实现原理》中&#xff0c;我们已经掌握了 MyBatis 一级缓存的配置&#xff08;虽然…

使用AOP思想实现开闭原则下的流水日志输出

主要实现思想&#xff1a; 通过实现Convert接口来抽取公共组件&#xff0c;获取想要的标准模型。 现在有两个订单场景&#xff0c;一个保存订单&#xff0c;一个为更新订单。构造如下的服务类&#xff1a; import org.springframework.stereotype.Service;Service public clas…

pwm 呼吸灯(如果灯一直亮或者一直灭)

&#xff08;这个文章收藏在我的csdn keil文件夹下面&#xff09; 如果这样设置预分频和计数周期&#xff0c;那么算出来的pwm频率如下 人眼看起来就只能是一直亮或者灭&#xff0c;因为pwm的频率太高了&#xff0c;但是必须是频率够高&#xff0c;才能实现呼吸灯的缓慢亮缓慢…

Django之项目开发(一)

一、项目的生命周期介绍 传统Web 项目的生命周期指的是从开始构建一个网站到该网站完成并维护的整个过程。通常情况下,Web 项目的生命周期包括以下几个阶段 需求分析阶段:在这个阶段,项目组会与客户进行沟通,确定网站的功能、内容和设计。 主要由产品经理参与产出思路与方案…

ChatGPT-4o大语言模型优化、本地私有化部署、从0-1搭建、智能体构建等高级进阶

目录 第一章 ChatGPT-4o使用进阶 第二章 大语言模型原理详解 第三章 大语言模型优化 第四章 开源大语言模型及本地部署 第五章 从0到1搭建第一个大语言模型 第六章 智能体&#xff08;Agent&#xff09;构建 第七章 大语言模型发展趋势 第八章 总结与答疑讨论 更多应用…

Nginx auth 的权限验证

基本流程 整个流程为&#xff1b;以用户视角访问API开始&#xff0c;进入 Nginx 的 auth 认证模块&#xff0c;调用 SpringBoot 提供的认证服务。根据认证结果调用重定向到对应的 API 接口或者 404 页面。 查看版本保证有 Nginx auth 模块 由于 OpenAI 或者本身自己训练的一套…

数据结构(其一)--基础知识篇

1. 数据结构三要素 1.1 数据结构的运算 即&#xff0c;增删改查 1.2 数据结构的存储结构 2. 数据类型&#xff0c;抽象数据类型 数据类型&#xff1a; &#xff08;1&#xff09;. 原子类型&#xff1a;bool、int... &#xff08;2&#xff09;. 结构类型&#xff1a;类、…

Linux多线程(中)

Linux多线程&#xff08;中&#xff09; 1.Linux线程互斥1.1互斥量的接口1.1.1初始化互斥量1.1.2销毁互斥量1.1.3互斥量加锁和解锁 1.2修改代码1.3互斥量实现原理 2.可重入VS线程安全3.死锁4.Linux线程同步5.生产者消费者模型 &#x1f31f;&#x1f31f;hello&#xff0c;各位…

Java 自定义集合常量

文章目录 Java 自定义集合常量一、普通方法自定义集合常量信息1、定义 Map 集合信息&#xff08;1&#xff09;方法一&#xff1a;使用静态代码块&#xff08;2&#xff09;方法二&#xff1a;简单定义 Map 常量 2、定义 List 集合信息3、定义 Set 集合信息 二、通过 Collectio…

用win的控制台去远程连接虚拟机linux的终端

以Ubuntu为例&#xff0c;首先确保Ubuntu已经安装了ssh服务 sudo apt-get install openssh-server输入密码 安装完毕后查看ssh状态是否开启 sudo systemctl status ssh 显示绿色激活状态&#xff0c;可以关闭或开启 对应start和stop winr打开win端控制台 输入 ssh -p 22 …

python-22-零基础自学python-数据分析基础 打开文件 读取文件信息

学习内容&#xff1a;《python编程&#xff1a;从入门到实践》第二版 知识点&#xff1a; 读取文件 、逐行读取文件信息等 练习内容&#xff1a; 练习10-1:Python学习笔记 在文本编辑器中新建一个文件&#xff0c;写几句话来总结一下你至此学到的Python知识&#xff0c;其中…

ASCII码对照表(Matplotlib颜色对照表)

文章目录 1、简介1.1 颜色代码 2、Matplotlib库简介2.1 简介2.2 安装2.3 后端2.4 入门例子 3、Matplotlib库颜色3.1 概述3.2 颜色图的分类3.3 颜色格式表示3.4 内置颜色映射3.5 xkcd 颜色映射3.6 颜色命名表 4、Colorcet库5、颜色对照表结语 1、简介 1.1 颜色代码 颜色代码是…

声明队列和交换机 + 消息转换器

目录 1、声明队列和交换机 方法一&#xff1a;基于Bean的方式声明 方法二&#xff1a;基于Spring注解的方式声明 2、消息转换器 1、声明队列和交换机 方法一&#xff1a;基于Bean的方式声明 注&#xff1a;队列和交换机的声明是放在消费者这边的&#xff0c;这位发送的人他…

OSS存储桶漏洞总结

简介 OSS&#xff0c;对象存储服务&#xff0c;对象存储可以简单理解为用来存储图片、音频、视频等非结构化数据的数据池。相对于主机服务器&#xff0c;具有读写速度快&#xff0c;利于分享的特点。 OSS工作原理&#xff1a; 数据以对象&#xff08;Object&#xff09;的形式…

Java高级重点知识点-21-IO、字节流、字符流、IO异常处理、Properties中的load()方法

文章目录 IOIO的分类 字节流字节输出流【OutputStream】字节输入流【InputStream】图片复制 字符流字符输入流【FileReader】字符输出流【FileWriter】 IO异常的处理&#xff08;扩展知识&#xff09;Properties属性集(java.util) IO Java中I/O操作主要是指使用 java.io 包下的…

iOS中多个tableView 嵌套滚动特性探索

嵌套滚动的机制 目前的结构是这样的&#xff0c;整个页面是一个大的tableView, Cell 是整个页面的大小&#xff0c;cell 中嵌套了一个tableView 通过测试我们发现滚动的时候&#xff0c;系统的机制是这样的&#xff0c; 我们滑动内部小的tableView, 开始滑动的时候&#xff0c…

想知道你的电脑能不能和如何升级RAM吗?这里有你想要的一些提示

考虑给你的电脑增加更多的RAM,但不确定从哪里开始?本指南涵盖了有关升级Windows PC或笔记本电脑中RAM的所有信息。 你需要升级RAM吗 在深入研究升级RAM的过程之前,评估是否需要升级是至关重要的。你是否经历过系统滞后、频繁的BSOD错误或应用程序和程序突然崩溃?这些症状…

Lock与ReentrantLock

在 Java 中&#xff0c;Lock 接口和 ReentrantLock 类提供了比使用 synchronized 方法和代码块更广泛的锁定机制。 简单示例&#xff1a; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockExample {pr…

聊一下Maven打包的问题(jar要发布)

文章目录 一、问题和现象二、解决方法&#xff08;1&#xff09;方法一、maven-jar-pluginmaven-dependency-plugin&#xff08;2&#xff09;方法二、maven-assembly-plugin 一、问题和现象 现在的开发一直都是用spring boot&#xff0c;突然有一天&#xff0c;要自己开发一个…

【CUDA】

笔者在学习Softmax实现时遇到了一个问题&#xff0c;很多文章直接将softmax的计算分成了五个过程&#xff0c;而没有解释每个过程的含义&#xff0c;尤其是在阅读这篇文章时&#xff0c;作者想计算最基本的softmax的效率&#xff0c;以展示可行的优化空间&#xff1a; 贴一个g…