Arrays, Lambda、方法引用、算法

1,Arrays类

1,Arrays基本使用

Arrays是操作数组的工具类,它可以很方便的对数组中的元素进行遍历、拷贝、排序等操作。

Arrays中常见的方法(很不全,只是为了引出Lambda):

方法名说明
public static String toString(类型[] arr)返回数组的内容
static int binarySearch(类型[] a, 类型 key)使用二分搜索法从指定的数组中搜索指定值对应的索引位置。
public static int[] copyOfRange(类型[] arr, 起始索引, 结束索引)拷贝数组(指定范围)
public static copyOf(类型[] arr, int newLength)拷贝数组
public static setAll(double[] array, IntToDoubleFunction generator)把数组中的原数据改为新数据
public static void sort(类型[] arr)对数组进行排序(默认是升序排序)
	    // 1、public static String toString(类型[] arr): 返回数组的内容
        int[] arr = {10, 20, 30, 40, 50, 60};
        System.out.println(Arrays.toString(arr));

        // 2、public static 类型[] copyOfRange(类型[] arr, 起始索引, 结束索引) :拷贝数组(指定范围,包前不包后)
        int[] arr2 = Arrays.copyOfRange(arr, 1, 4);
        System.out.println(Arrays.toString(arr2));

        // 3、public static copyOf(类型[] arr, int newLength):拷贝数组,可以指定新数组的长度。
        int[] arr3 = Arrays.copyOf(arr, 10);
        System.out.println(Arrays.toString(arr3));

        // 4、public static setAll(double[] array, IntToDoubleFunction generator):把数组中的原数据改为新数据又存进去。
        double[] prices = {99.8, 128, 100};
        //                  0     1    2
        // 把所有的价格都打八折,然后又存进去。
        Arrays.setAll(prices, new IntToDoubleFunction() {
            @Override  /* 这里的value是数组中每个元素的索引*/
            public double applyAsDouble(int value) {
                // value = 0  1  2
                return prices[value] * 0.8;
            }
        });
        System.out.println(Arrays.toString(prices));

        // 5、public static void sort(类型[] arr):对数组进行排序(默认是升序排序)
        Arrays.sort(prices);
        System.out.println(Arrays.toString(prices));
2,Arrays操作对象数组

上面的sort可以对基本数据类型进行排序,但是都是按照java定义的顺序和规则,这个是我们更改不了的,那么有没有一种方法实现自定义的排序呢?

答案是有的:而且还有两种方式,一是实现 Comparable重写其中的compareTo方法,因为Arrays类中的sort方法底层调用的就是compare方法,所以知道我们重写这个方法,然后感觉我们的规则,就会按照我们创建的规则进行排序。

**需求描述:**有一个Student类,对其进行排序,先按照年龄进行排序,如果年龄相同再根据姓名进行排序。按照以往的肯定是不行的,会报错,所以就需要我们自己来重新定义一下这个方法。

  • **排序方式1:**让Student类实现Comparable接口,同时重写compareTo方法。Arrays的sort方法底层会根据compareTo方法的返回值是正数、负数、还是0来确定谁大、谁小、谁相等。代码如下:
public class Student implements Comparable<Student>{
    private String name;
    private double height;
    private int age;
    
    //...get、set、空参数构造方法、有参数构造方法...

    // 指定比较规则
    //1,始终为减法运算 
   // 用当前对象的属性中的数值,减去参数中的对象的数值,为升序
    // 用参数对象中的属性的数值减去当前对象对应属性的数值  为降序
    // this  o

    @Override
    public int compareTo(Student o) {
        //     这里的i如果是等于零,那么说明两个的age相等,然后在比较姓名<>
        int i = this.age - o.age;
        if (i == 0){
            i = this.name.compareTo(o.name);
        }
        return i; // 按照年龄升序排列
        
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", height=" + height +
                ", age=" + age +
                '}';
    }
}

主方法:

public static void main(String[] args) {
        Student[] students = {
                new Student("zhangsan", 169.5, 23),
                new Student("lisi", 163.8, 26),
                new Student("wanger", 163.8, 26),
                new Student("mazi", 167.5, 24)};

        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
 }

**结果:**先按年龄的升序,如果年龄相同按照名字的升序

[Student{name='zhangsan', height=169.5, age=23}, 
Student{name='mazi', height=167.5, age=24}, 
Student{name='lisi', height=163.8, age=26}, 
Student{name='wanger', height=163.8, age=26}]

**排序方式2:**在调用Arrays.sort(数组,Comparator比较器);时,除了传递数组之外,传递一个Comparator比较器对象。Arrays的sort方法底层会根据Comparator比较器对象的compare方法方法的返回值是正数、负数、还是0来确定谁大、谁小、谁相等。代码如下

Arrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                int i = o1.getAge() - o2.getAge();
                if (i == 0){
                    i = o2.getName().compareTo(o2.getName());
                }
                return i; // 按照年龄升序排列
            }
        });
        System.out.println(Arrays.toString(students));
    }

结果同上:

[Student{name='zhangsan', height=169.5, age=23}, 
Student{name='mazi', height=167.5, age=24}, 
Student{name='lisi', height=163.8, age=26}, 
Student{name='wanger', height=163.8, age=26}]

2,lambda表达式

1,lambda表达式基本使用

作用:用于简化匿名内部类代码的书写。

格式:

(被重写方法的形参列表) -> {
    被重写方法的方法体代码;
}

注意:在使用Lambda表达式之前,必须先有一个接口,而且接口中只能有一个抽象方法。(注意:不能是抽象类,只能是接口),被@FunctionInterface修饰

比如:有这样的一个接口

@FunctionalInterface
public interface Swimming{
    void swim();
}

有了以上的Swimming接口之后,接下来才能再演示,使用Lambda表达式,简化匿名内部类书写。

//      1.创建一个Swimming接口的匿名内部类对象
        Swimming swimming = new Swimming(){
            @Override
            public void swim() {
                System.out.println("自由泳进行时~~~~");
            }
        };
//      调用
        swimming.swim();

//      使用lambda这样这样写
        Swimming swimming1 = ()-> System.out.println("蛙泳进行时~~~");
	    swimming1.swim();

上面是初体验:

下面就对,Lambda使用的前提,以及什么时候可以用Lambda表达式,表达格式是怎样的做一个叙述:

首先就是推导环境: 就是能够通过当前的语境知道,实现的接口是哪一个,并且使用的方法是哪一个其实当知道了使用的接口,有因为Lambda能够使用的情况只能有一个方法,所以这个方法就显而易见,肯定是那一个。这是前提条件

那么什么时候能够使用呢?

也就是当匿名内部类要实现的接口只有一个方法的时候,就可以使用。

2,lambda表达式省略规则

表达格式:

(被重写方法的形参列表) -> {
	被重写方法的方法体代码。
}
  • 参数类型可以省略不写。

  • 如果只有一个参数,参数类型可以省略,同时()也可以省略。

  • 如果Lambda表达式中的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号!此时,如果这行代码是return语句,也必须去掉return不写。

下面是Arrays工具类中的方法:对数组中的数据自定义的进行修改,需要传入一个修改规则,匿名内部类的写法:对数组中的每一个数据都扩大两倍

  double[] scores = {99.8, 128.0, 100.0};

  Arrays.setAll(scores, new IntToDoubleFunction() {
      @Override
      public double applyAsDouble(int value) {
        return scores[value] * 2;
      }
  });
  System.out.println(Arrays.toString(scores));

lambda表达式的写法:

double[] scores = {99.8, 128.0, 100.0};
Arrays.setAll(scores, i-> scores[i] * 2) ;

研究一下这里省略的信息:

首先只有一个参数,所以小括号可以省略, 方法体之后一行代码 { } ,return ;

嘎嘎香,但是要知道接口中的方法。

3,JDK8新特性(方法引用)

1,静态方法调用

类名::静态方法

首先我们先看一下之前Lambda的表示:

传入一个students数组,通过lambda表达式可以这样表示

    // 使用Lambda简化后的形式
    Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge());

可以观察到这里其实就是一个方法,有一种情况,就是这个方法的实现自己或者API中定义的有的话,我们就可以使用这个方法,如果是静态的可以通过类名::静态方法的方式来实现。

比如说对于排序规则我们之前已经定义过了,这个时候我们还想用这个方法,这个时候我们就可以直接使用,代码如下:有一个CompareByData类,中有一个静态的方法

public class CompareByData {
    public static int compareByAge(Student o1, Student o2){
        return o1.getAge() - o2.getAge(); // 升序排序的规则
    }
}

如果我们使用静态方法,可以这样表示:

//静态方法引用:类名::方法名
Arrays.sort(students, CompareByData::compareByAge);
2,实例方法调用

实例方法,就是如果类中的方法不是静态这个时候我们就不可以直接使用类名,来使用其中的方法,这个时候就需要我们自己创建对象之后在进行处理。

如下

public class CompareByData {
    public int compareByAge(Student o1, Student o2){
        return o1.getAge() - o2.getAge(); // 升序排序的规则
    }
}
//静态方法引用:类名::方法名
Arrays.sort(students, new CompareByData()::compareByAge);
3,特定类型的方法调用

特定类型的方法调用,可能我们也会发现,还有一种情况,就是当数组中的类型,和第二参数要使用的类是同一个类时,这个时候,这个时候,虽然具体的类中没有对应的静态的方法,但是这个时候我们也可以向静态方法一样的调用。通过需求我们来看这问题.

需求如下:有这样一个字符串数组,我们要把他们进行排序,排序规则是,忽略字母大小写升序排序。那么代码我们就可以写成这样,因为我们知道String中有这样的一个方法,而且数组中的数据又是String类型,所以这个时候不用new ,直接 类名::方法名,这也算是一个特例。

  public static void main(String[] args) {
        String[] arr = {"aabb","Ab","ba","bb","ccccc","aaaaaaaa"};

        Arrays.sort(arr,String::compareToIgnoreCase);
        System.out.println(Arrays.toString(arr));
  }

4,常见算法

1,算法概述

算法其实是解决某个实际问题的过程和方法。比如百度地图给你规划路径,计算最优路径的过程就需要用到算法。再比如你在抖音上刷视频时,它会根据你的喜好给你推荐你喜欢看的视频,这里也需要用到算法。学习算法主要目的是训练我们的编程思维,还有就是面试的时候,面试官也喜欢问一下算法的问题来考察你的技术水平

2,冒泡排序

冒泡排序的流程

冒泡排序核心思路:每次将相邻的两个元素继续比较
如下图所示:
   第一轮比较 3次
   第二轮比较 2次
   第三轮比较 1次

在这里插入图片描述

public class Test1 {
    public static void main(String[] args) {
        // 1、准备一个数组
        int[] arr = {5, 2, 3, 1};

        // 2、定义一个循环控制排几轮,两个数比较,很明显是总长度-1
        for (int i = 0; i < arr.length - 1; i++) {

            // 3、定义一个循环控制每轮比较几次。
            for (int j = 0; j < arr.length - i - 1; j++) {
                // 判断当前位置的元素值,是否大于后一个位置处的元素值,如果大则交换。
                if(arr[j] > arr[j+1]){
                    int temp = arr[j + 1];
                    arr[j + 1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }
}
3,选择排序

选择排序算法的流程:选择排序的核心思路是,每一轮选定一个固定的元素,和其他的每一个元素进行比较;经过几轮比较之后,每一个元素都能比较到了。

在这里插入图片描述

ublic class Test2 {
    public static void main(String[] args) {
        // 1、准备好一个数组
        int[] arr = {5, 1, 3, 2};
        //           0  1  2  3

        // 2、控制选择几轮
        for (int i = 0; i < arr.length - 1; i++) {
            // i = 0 第一轮    j = 1 2 3
            // i = 1 第二轮    j = 2 3
            // i = 2 第三轮    j = 3
            // 3、控制每轮选择几次。
            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;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }
}
4,查找算法

查找算法叫做二分查找,二分查找的主要特点是,每次查找能排除一般元素,这样效率明显提高。但是二分查找要求比较苛刻,它要求元素必须是有序的,否则不能进行二分查找。

1步:先定义两个变量,分别记录开始索引(left)和结束索引(right)2步:计算中间位置的索引,mid = (left+right)/2;3步:每次查找中间mid位置的元素,和目标元素key进行比较
		如果中间位置元素比目标元素小,那就说明mid前面的元素都比目标元素小
			此时:left = mid + 1
    	如果中间位置元素比目标元素大,那说明mid后面的元素都比目标元素大
    		此时:right = mid - 1
		如果中间位置元素和目标元素相等,那说明mid就是我们要找的位置
			此时:把mid返回		
注意:一搬查找一次肯定是不够的,所以需要把第1步和第2步循环来做,只到left>end就结束,如果最后还没有找到目标元素,就返回-1.

在这里插入图片描述

public class Test3 {
    public static void main(String[] args) {
        // 1、准备好一个数组。
        int[] arr = {7, 23, 79, 81, 103, 127, 131, 147};

        System.out.println(binarySearch(arr, 150));

        System.out.println(Arrays.binarySearch(arr, 81));
    }

    public static int binarySearch(int[] arr, int data){
        // 1、定义两个变量,一个站在左边位置,一个站在右边位置
        int left = 0;
        int right = arr.length - 1;

        // 2、定义一个循环控制折半。
        while (left <= right){
            // 3、每次折半,都算出中间位置处的索引
            int middle = (left + right) / 2;
            // 4、判断当前要找的元素值,与中间位置处的元素值的大小情况。
            if(data < arr[middle]){
                // 往左边找,截止位置(右边位置) = 中间位置 - 1
                right = middle - 1;
            }else if(data > arr[middle]){
                // 往右边找,起始位置(左边位置) = 中间位置 + 1
                left = middle + 1;
            }else {
                // 中间位置处的元素值,正好等于我们要找的元素值
                return middle;
            }
        }
        return -1; // -1特殊结果,就代表没有找到数据!数组中不存在该数据!
    }
}

其实很好理解,在理解三个指针之后,可以自己画个图,然后试着移动一下指针,就显而易见了。加油呀😃

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yfs1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值