Arrays和Lambda表达式

Arrays类

Arrays类是操作数组的工具类,其构造方法被私有化,不允许从外部创建对象,所有的方法都是静态的(构造方法被私有化,成员方法为静态的)

  • 常用方法
package com.an.a;

import java.util.Arrays;

public class ArraysTest {
    public static void main(String[] args) {
      /*
        常见方法:
        public static String toString(数组) 把数组拼接成一个字符串
        public static int binarySerach(数组,查找的元素) 二分查找数组中的元素
        public static int[] copyOf(原数组,新数组长度) 拷贝数组
        public static int[] copyRange(原数组,起始索引,结束索引)拷贝数组(指定范围)
        public static void fill(数组,元素) 填充数组
        public static void sort(数组) 按照默认的方式进行数组排序
        public static void sort(数组,排序规则) 按照指定的规则排序
       */
        //1.将数组转化为字符串
        System.out.println("----------------------------toString--------------------------------------------------");
        int a[]={1,3,4,5,6,9};
         String s = Arrays.toString(a);//将数组转化为字符串
        System.out.println(s);//[1, 3, 4, 5, 6, 9]

        //2.二分查找数组中的元素
        //二分查找细节:
        //1.进行查找之前数组中的元素必须是有序的(java这里必须是升序的)(这里java写的方法在排序之前自己都实现了)
        //2.如果要查询的元素在数组中存在,返回该元素的真实索引
        //如果要查询的元素不存在,返回的是 -插入点(即如果将该元素放进数组中有序后的索引)-1
        //解释:为什么不存在要这样返回:如果我们所查询的元素不存在但是它的插入点在0索引-0还是0就会带来歧义 -1可以避免这个问题
        System.out.println("-------------------------------------binarySerach------------------------------------------------");
        int b[]={2,3,4,5,9,11};
        System.out.println(Arrays.binarySearch(b,2));//0
        System.out.println(Arrays.binarySearch(b,11));//5
        System.out.println(Arrays.binarySearch(b,12));//-7
        //数组拷贝
        System.out.println("-----------------------------------------copyOf------------------------------------------");
        /*
        参数1:老数组
        参数2:新数组的长度
        方法底层会根据第二个参数来创建数组
        如果新数组的长度小于老数组的长度  会部分拷贝
        如果新数组的长度大于老数组的长度  会完全拷贝 并在多余的位置补上默认值
        如果新数组的长度等于老数组的长度  会完全拷贝
         */
        int c[]={1,2,3,4,5,6,7};
        System.out.println(Arrays.toString(Arrays.copyOf(c, 4)));//[1, 2, 3, 4]
        System.out.println(Arrays.toString(Arrays.copyOf(c, 10)));//[1, 2, 3, 4, 5, 6, 7, 0, 0, 0]
        System.out.println(Arrays.toString(Arrays.copyOf(c, 7)));//[1, 2, 3, 4, 5, 6, 7]
        //指定返回的拷贝数组
        //包头不包尾
        System.out.println("---------------------------copyRange-----------------------------------");
        int d[]={1,2,3,4,5};
        System.out.println(Arrays.toString(Arrays.copyOfRange(d, 0, 4)));//[1, 2, 3, 4](包头不包尾)

        //fill填充数组
        System.out.println("--------------------------------fill----------------------------------------");
        int e[]=new int[10];
        Arrays.fill(e,6);//用6来填充数组
        System.out.println(Arrays.toString(e));//[6, 6, 6, 6, 6, 6, 6, 6, 6, 6]
        //sort排序:默认情况下给基本数据类型按照升序排序(底层使用快排)
        System.out.println("--------------------------------------------sort---------------------------");
        int w[]={3,1,6,2,5,10};
        Arrays.sort(w);
        System.out.println(Arrays.toString(w));//[1, 2, 3, 5, 6, 10]


    }
}

我们知道sort方法是按照默认的比较规则进行比较的,默认的规则是按照升序排序的,如果此时我们需要降序排序,怎么办呢?sort的一个重载方法可以解决这个问题

package com.an.a;

import java.util.Arrays;
import java.util.Comparator;

public class ArraysTest {
    public static void main(String[] args) {
      /*

        public static void sort(数组,排序规则) 按照指定的规则排序
        参数一:要排序的数组
        参数二:排序的规则
        只能给引用数据类型的数组排序,
        如果数组是基本数据类型需要变成其对应的包装类
       */
      Integer a[]={2,1,4,3,9,6,7};//这里注意为包装类

    Arrays.sort(a, new Comparator<Integer>() {
        //第二个参数是一个接口,所以我们在调用方法的时候,需要传递这个接口的实现类对象,作为排序的规则
        //但是这个实现的类,我们只需要使用一次,所以没有必要取单独编写一个类,直接使用匿名内部类的方式就可以了
        /*
        底层原理:
        1.利用插入排序+二分查找来排序的
        默认把0索引的数据看成是有序的序列,把1索引到最后认为是无序的序列
        遍历无序序列得到里面的每一个元素,假设当前遍历得到的元素是A元素
        把A往有序序列中进行插入,在插入的时候,是利用二分查找确定A的插入点
        拿着A跟插入点的元素进行比较,比较的规则就是compare方法的方法体
        如果方法的返回值负数,拿着A继续跟前面的数据进行比较
        如果方法的返回值正数,拿着A继续跟后面的数据进行比较
        如果方法的返回值0,拿着A继续跟后面的数据进行比较
        直到能确定A的位置为止
        compare方法的形式参数:
        参数1:o1 表示在无序序列中遍历得到的每一个元素
        参数2:o2 有序序列中的元素
        返回值:
        负数:表示当前要插入的元素是小的 ,放在前面
        正数:表示当前要插入的元素是大的 ,放在后面
        0:表示当前插入元素跟现在元素一样大,也会发在后面
         */
        @Override
        public int compare(Integer o1, Integer o2) {
            System.out.println("-----------------------------");
            System.out.println("o1:"+o1);
            System.out.println("o2:"+o2);
            return o2-o1;
            //结合程序运行结果和插入排序+二分查找 来理解排序的过程
            //简单理解:o1-o2:升序排列
            //o2-o1:降序排列
        }
    });
    //打印排序结果
        System.out.println(Arrays.toString(a));//[9, 7, 6, 4, 3, 2, 1]
    }
}

Lambda表达式

  • 体验Lambda表达式

    对以上排序的代码进行简化处理
    Lambda表达式简化匿名内部类的书写
package com.an.a;

import java.util.Arrays;
import java.util.Comparator;

public class LambdaTest {
    public static void main(String[] args) {
       Integer a[]={2,1,4,9,7,3};
        /*Arrays.sort(a, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;
            }
        });[9, 7, 4, 3, 2, 1]*/
        //对以上排序的过程进行简化
    Arrays.sort(a,(Integer o1,Integer o2)->{
            return o2-o1;
        }
    );//[9, 7, 4, 3, 2, 1]
        System.out.println(Arrays.toString(a));
    }
}


  • Lambda表达式的格式

    不关心谁去做,只关系方法体

如果满足这个要求,加上这个注解后不会报错,如果不满足这个要求加上这个注解就会报错

package com.an.a;

import java.util.Arrays;
import java.util.Comparator;

public class LambdaTest {
    public static void main(String[] args) {
       //测试Lambda表达式是基本用法
        /*
            Lambda注意点:
            1.Lambda表达式可以用来简化匿名内部类的书写
            2.Lambda表达式只能简化函数式接口的匿名内部类的写法
            2.函数式接口:
                有且仅有一个抽象方法的接口叫函数式接口,该接口可以加@FunctionalInterface进行注解
         */
        /*
            利用匿名内部类的形式去调用下面的方法:
            调用一个方法的时候,如果该方法的形参是一个接口,那么我们要传递这个接口的实现类对象
            如果实现类对象只要用到一次,就可以用匿名内部类的形式进行书写
         */
       /* method(//new Swim() {  多删除了一个{后面要删除一个}
            @Override
            public void swimming//() {
                System.out.println("hello world");//hello world
            }
        });*/
       //用Lambda表达式进行改写
         method(()-> {
                System.out.println("hello world");//hello world
            }
        );
    }
    public static void method(Swim s){
        s.swimming();
    }
  @FunctionalInterface //函数式接口注解(如果不符合函数式接口的要求注解处将会报错)
    interface Swim{
        public abstract void swimming();
       
    }
}

Lambda表达式的省略写法

 method(()-> {
                System.out.println("hello world");//hello world
            }
        );
    }

函数式的编程重要的是函数体,而且一定要是函数式的接口,通过以上的写法,如果我们不是函数式的接口,则说明我们的接口里面的抽象方法不止一个,这是我们所指示的方法体 System.out.println("hello world");//hello world就不知道是哪个抽象函数的重写方法体了,这就造成了混乱

Lambda表达式的省略规则

package com.an.a;

import java.util.Arrays;
import java.util.Comparator;

public class LambdaTest2 {
    public static void main(String[] args) {
        /*
            Lambda表达式省略规则:(都是对覆写的方法进行优化的)
            1.参数类型可以省略不写(需要同时省略)
            2.如果只有一个参数,参数类型可以省略,同时()也可以省略
            3.如果Lambda表达是方法体只有一行,大括号 分号,return可以省略不写,但是需要同时省略
         */
        //以Arrays类中的sort方法为例
        Integer[]arr = {3,2,5,4,9,8};
        //不使用Lambda表达式
        Arrays.sort(arr, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;
            }
        });
        //Lambda表达式的完整写法
        Arrays.sort(arr,(Integer o1, Integer o2)-> {
                return o2-o1;
            }
        );
       //Lambda表达式的省略写法
        Arrays.sort(arr,( o1,  o2)-> o2-o1); //符合规则1 和规则3
    }
}


Lambda表达式的练习

package com.an.a;

import java.util.Arrays;
import java.util.Comparator;

public class LambdaTest {
    public static void main(String[] args) {
      /*
        定义一个数组储存一些字符串,利用    Arrays中的sort进行排序
        要求:
        按照字符串的长度进行排序,短的在前面,长的在后面
       */
        String[]arr={"cc","c","cccc","ccc"};
        //1.不使用Lambda
        Arrays.sort(arr, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.length()-o2.length();//按照字符串长度的升序进行排序
            }
        });
       //2.Lambda表达式的完整模式
        Arrays.sort(arr, (String o1, String o2)-> {
                return o1.length()-o2.length();//按照字符串长度的升序进行排序
            }
        );
        //3.Lambda表达式的简化版本
        /*
        简化规则:
        1.小括号中:参数的数据类型都可以省略,如果只有一个参数参数的小括号也可以省略
        2.大括号:如果方法体只有一行:大括号 分号 return可以省略(必须同时省略)
         */
        Arrays.sort(arr, ( o1,  o2)-> o1.length()-o2.length());
        
    }
}

5个算法的小练习

第一题(和Lambda相关)

package com.an.a;

import java.util.Arrays;
import java.util.Comparator;

/*String str1="a";
         String str2="b";
         int result =str1.compareTo(str2);//实际是用str1-str2 即按照升序进行的
         System.out.println(result);
*/
public class LambdaPractice {
    public static void main(String[] args) {
     /*
     定义数组并储存一些女朋友的对象,利用Arrays中的sort方法进行排序
     要求:
     1.女朋友属性有姓名 年龄 身高
     2.按照年龄的大小进行排序,年龄一样按照身高进行排序,姓名一样按照姓名的字母进行排序
     (姓名中不要有中文或特殊字符,涉及后面的知识)
      */
        //1.创建3个女朋友的对象
        GirlFriends grirl1 =new GirlFriends("angelababy",23,167);
        GirlFriends grirl2 =new GirlFriends("xiaoshishi",23,163);
        GirlFriends grirl3 =new GirlFriends("xiaodandan",22,153);
        GirlFriends[]arr ={grirl1,grirl2,grirl3};//此时的数组中放匿名对象也是可以的
        //2.利用sort方法进行排序
        /*Arrays.sort(arr, new Comparator<GirlFriends>() {
            //按照年龄的大小进行排序,年龄一样按照身高进行排序,姓名一样按照姓名的字母进行排序
            @Override
            public int compare(GirlFriends o1, GirlFriends o2) {
                 double temp = o1.getAge() - o2.getAge();
               temp=temp==0?o1.getHeight()-o2.getHeight():temp;
               temp=temp==0?o1.getName().compareTo(o2.getName()):temp;


                //return (int)temp;// 这里如果直接返回temp  如果temp=0.1 返回的化将会强制转为0 导致结果错误
                if(temp>0){
                    return 1;
                }else if(temp<0){
                    return -1;
                }else {
                    return 0;
                }

            }

        });*/
       //2.使用Lambda进行简写
        Arrays.sort(arr, ( o1,  o2)-> {
                double temp = o1.getAge() - o2.getAge();
                temp=temp==0?o1.getHeight()-o2.getHeight():temp;
                temp=temp==0?o1.getName().compareTo(o2.getName()):temp;


                //return (int)temp;// 这里如果直接返回temp  如果temp=0.1 返回的化将会强制转为0 导致结果错误
                if(temp>0){
                    return 1;
                }else if(temp<0){
                    return -1;
                }else {
                    return 0;
                }

            }

        );



    }
}

为什么在比较姓名的时候要调用CompareTo方法

compareTo方法是Comparable接口中的抽象方法,在所有的包装类和String类中都实现了该接口,并且覆写了compareTo方法,可以使用默认的规则对该类型的数据进行比较操作。我们在比较自己写的GirlFrinds类中的各项属性进行比较,基础数据类型只需要相减得出0 1 -1 即可,但是姓名是String类型,其默认的比较规则不是简单的升序,而是按照Ascii码的顺序进行排序,所有需要调用String类的compareTo方法进行排序,得出0 1 -1

posted @ 2023-01-07 13:53  一往而深,  阅读(107)  评论(0编辑  收藏  举报