一、lambda表达式

1、概念

  1. lambda表达式, Java8的一个新特性, 也是Java8中最值得学习的新特性之一。
  2. lambda表达式, 从本质来讲, 是一个匿名函数。 可以使用这个匿名函数, 实现接口中的方法。 对接口进行非常简洁的实现, 从而简化代码。

2、初识

  1. package com.qfedu.day10;
  2. /**
  3. * @Author laoyan
  4. * @Description TODO
  5. * @Date 2022/3/14 9:07
  6. * @Version 1.0
  7. */
  8. public interface SingleReturnSingleParameter {
  9. int test(int a);
  10. }
  1. package com.qfedu.day10;
  2. /**
  3. * @Author laoyan
  4. * @Description TODO
  5. * @Date 2022/3/14 9:09
  6. * @Version 1.0
  7. */
  8. /**
  9. * 某个接口,之前如果想调用的话,必须实现该接口
  10. */
  11. public class SingleReturnSingleParameterImpl implements SingleReturnSingleParameter{
  12. @Override
  13. public int test(int a) {
  14. return a * a;
  15. }
  16. }

可以简化为:

  1. package com.qfedu.day10;
  2. /**
  3. * @Author laoyan
  4. * @Description TODO
  5. * @Date 2022/3/14 9:10
  6. * @Version 1.0
  7. */
  8. public class MainTest {
  9. public static void main(String[] args) {
  10. /**
  11. * 第一种写法
  12. */
  13. SingleReturnSingleParameter singleReturnSingleParameter = new SingleReturnSingleParameterImpl();
  14. int test = singleReturnSingleParameter.test(10);
  15. System.out.println(test);
  16. /**
  17. * 接口new了
  18. * 如果我们为了调用某个接口,而去实现这个类,其实这个类叫什么名字已经不重要了,而是具体的实现代码
  19. *
  20. * 以下是使用了匿名类,匿名类就是没有名字的类,因为叫什么不重要。
  21. *
  22. * lambda表达: 直接复制小口号 ,写死右箭头, 复制大括号即可
  23. *
  24. * -> 为什么呢 λ 简化为 ->
  25. */
  26. SingleReturnSingleParameter singleReturnSingleParameter1 = new SingleReturnSingleParameter() {
  27. @Override
  28. public int test(int a) {
  29. return a*a;
  30. }
  31. };
  32. /**
  33. * 通过lambda表达式简化以上代码
  34. */
  35. SingleReturnSingleParameter singleReturnSingleParameter2 = (int a) -> {
  36. return a*a;
  37. };
  38. SingleReturnSingleParameter singleReturnSingleParameter3 = (a) -> {
  39. return a*a;
  40. };
  41. SingleReturnSingleParameter singleReturnSingleParameter4 = a -> a*a;
  42. }
  43. }

3、认真讲解lambda表达式
1)适用场景

  1. 虽然说, lambda表达式可以在一定程度上简化接口的实现。 但是, 并不是所有的接口都可以使用lambda表达式来简洁实现的。
  2. lambda表达式毕竟只是一个匿名方法。 当实现的接口中的方法过多或者过少的时候, lambda表达式都是不适用的。
  3. lambda表达式,只能实现函数式接口。
  4. 只能针对函数式接口,所谓的函数式接口就是一个接口中,只能有一个未实现的方法。

记住: 接口中有且仅有一个方法必须实现,称之为函数式接口

  1. // 这个接口中, 有且只有一个方法, 是实现类必须实现的, 因此是一个函数式接口
  2. interface Test1 {
  3. void test();
  4. }
  5. // 这个接口中, 实现类必须要实现的方法, 有两个! 因此不是一个函数式接口
  6. interface Test2 {
  7. void test1();
  8. void test2();
  9. }
  10. // 这个接口中, 实现类必须要实现的方法, 有零个! 因此不是一个函数式接口
  11. interface Test3 {
  12. }
  13. // 这个接口中, 虽然没有定义任何的方法, 但是可以从父接口中继承到一个抽象方法的。 是一个函数式接口
  14. interface Test4 extends Test1 {
  15. }
  16. // 这个接口, 虽然里面定义了两个方法, 但是defualt方法子类不是必须实现的。
  17. // 因此, 实现类实现这个接口的时候, 必须实现的方法只有一个! 是一个函数式接口。
  18. interface Test5 {
  19. void test5();
  20. default void test() {}
  21. }
  22. // 这个接口中的 toString 方法, 是Object类中定义的方法。
  23. // 此时, 实现类在实现接口的时候, toString可以不重写的! 因为可以从父类Object中继承到!
  24. // 此时, 实现类在实现接口的时候, 有且只有一个方法是必须要重写的。 是一个函数式接口!
  25. interface Test6 {
  26. void test6();
  27. String toString();
  28. }
  29. class A implements Test6{
  30. // 此处必须实现的方法只有一个,test6() ,toString() 可以选择性实现。
  31. }

2)快速判定一个接口是不是函数式接口的方法:
@FunctionalInterface
这个注解,在接口上一放,只要不报错,就说明该接口是函数式接口。

  1. @FunctionalInterface
  2. public interface AInterafce {
  3. int test1();
  4. String toString();
  5. }

我们的java中有一个叫做JUC的包—>java.util.concurrent 里面大量使用着函数式接口。
image.png
3) 语法

  1. (参数) -> {
  2. 方法体
  3. };
  4. 就是先复制方法的参数,小括号里面有什么就复制什么,紧跟一个拉姆达 -> ,后面使用大括号编写需要实现的内容即可。
  5. 这个是最标准的写法,在这个基础上可以进行简化。

口诀: 拷贝小括号,写死右箭头,落地大括号
4) 案例
根据函数式接口中,唯一的方法 有没有参数,有没有返回值,可以组合为多种情况:

  1. /**
  2. * @Author 千锋大数据教学团队
  3. * @Company 千锋好程序员大数据
  4. * @Date 2020/4/8
  5. * @Description
  6. */
  7. interface NoneReturnNoneParameter{
  8. // 因为接口中的方法,根据返回值的类型以及参数类型,排列组合可以分为很多种情况
  9. void test();
  10. }
  11. public class Syntax {
  12. public static void main(String[] args) {
  13. // 1. 无参、无返回值的方法实现
  14. NoneReturnNoneParameter lambda1 = () -> {
  15. System.out.println("无参、无返回值方法的实现");
  16. };
  17. lambda1.test();
  18. // 2. 有参、无返回值的方法实现
  19. NoneReturnSingleParameter lambda2 = (int a) -> {
  20. System.out.println("一个参数、无返回值方法的实现: 参数是 " + a);
  21. };
  22. lambda2.test(10);
  23. // 3. 多个参数、无返回值方法的实现
  24. NoneReturnMutipleParameter lambda3 = (int a, int b) -> {
  25. System.out.println("多个参数、无返回值方法的实现: 参数a是 " + a + ", 参数b是 " + b);
  26. };
  27. lambda3.test(10, 20);
  28. // 4. 无参、有返回值的方法的实现
  29. SingleReturnNoneParameter lambda4 = () -> {
  30. System.out.println("无参、有返回值方法的实现");
  31. return 666;
  32. };
  33. System.out.println(lambda4.test());
  34. // 5. 一个参数、有返回值的方法实现
  35. SingleReturnSingleParameter lambda5 = (int a) -> {
  36. System.out.println("一个参数、有返回值的方法实现: 参数是 " + a);
  37. return a * a;
  38. };
  39. System.out.println(lambda5.test(9));
  40. // 6. 多个参数、有返回值的方法实现
  41. SingleReturnMutipleParameter lambda6 = (int a, int b) -> {
  42. System.out.println("多个参数、有返回值的方法实现: 参数a是 " + a + ", 参数b是 " + b);
  43. return a * b;
  44. };
  45. System.out.println(lambda6.test(10, 20));
  46. }
  47. }

5) lambda 表达式有进一步简化的空间
1、参数可以简化
1)省略参数类型 (int a) 可以写成 (a)

  1. // 多个参数、无返回值的方法实现
  2. NoneReturnMutipleParameter lambda1 = ( a, b) -> {
  3. System.out.println("多个参数、无返回值方法的实现: 参数a是 " + a + ", 参数b是 " + b);
  4. };
  1. 2) 当只有一个参数时,可以省略小括号 (a) 变为 a
// 有参、无返回值的方法实现
NoneReturnSingleParameter lambda2 =  a  -> {
    System.out.println("一个参数、无返回值方法的实现: 参数是 " + a);
};

2、方法体可以简化
1) 如果方法体中,只有一句话,可以将{} 去掉

// 有参、无返回值的方法实现
NoneReturnSingleParameter lambda2 = a -> System.out.println("一个参数、无返回值方法的实现: 参数是 " + a);
 2) 如果方法体中只有一句话,并且这句话还是  return xxx ;<br />             除了{} 去掉,还必须去掉return;
SingleReturnMutipleParameter lambda3 = (a, b) -> a + b;

SingleReturnMutipleParameter lambda3 = a -> a * a;

二、集合

1、集合的整体印象

image.png
通过以上这个图,我们可以得到什么?
1) 常见的集合有三种List、Set 、Map
List和Set人家是一家子,他们的父亲叫做 Collection, Collection有个弟弟叫Map。跟Set,List 不是一个辈儿的。
2) 我们学习的集合是有重点的:
List —> ArrayList —> 存储有序的可以重复的单个元素。 —> 嫡子
Set —> HashSet —> 存储无序的,不可重复的元素。 —> 庶出
Map —> HashMap —> 是键值对存在的 (zhangsan ,23 ) (lisi, 50)

2、Collection 的常用方法

   不管是ArrayList 还是 HashSet  都是Colletion的子类,所以我们学习这个里面的方法就是在学习这个工具类。<br />   常用方法案例:
package com.qfedu.day10_2;

import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Predicate;

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/14 10:58
 * @Version 1.0
 */
public class DemoCollection {

    public static void main(String[] args) {
        /**
         *   Collection 是一个接口,所以我们不能直接new ,需要new一个实例化对象
         */
        Collection collection = new ArrayList();
        // 添加一个元素到集合中
        collection.add("java");
        System.out.println(collection);

        Collection collection2 = new ArrayList();
        collection2.add("python");
        collection2.add("bigdata");
        // 添加一个集合中的所有数据到另一个集合中
        collection.addAll(collection2);
        System.out.println(collection);
        // 从集合中删除一个元素
        collection.remove("python"); // 返回boolean 类型,表示删除是否成功
        System.out.println(collection);

        // 一个集合删除另一个集合的数据,只要有就删除
        //System.out.println(collection.removeAll(collection2));
        //System.out.println(collection);

        System.out.println(collection.retainAll(collection2));
        System.out.println(collection);

        // 清空所有元素
        collection.clear();

        collection.add("泰坦尼克号"); // 昨日重现
        collection.add("功夫"); //
        collection.add("怦然心动"); //

        // removeIf  只删除满足条件的元素
        /*collection.removeIf(new Predicate() {
            @Override
            public boolean test(Object o) {
                String fileName = (String) o;
                return fileName.contains("功");
            }
        });*/
        collection.removeIf(  o ->((String) o).contains("功"));
        System.out.println(collection);

        // 判断集合中是否包含某个元素
        System.out.println(collection.contains("bigdata"));

        // 返回集合中有多少个元素
        //  判断数组的长度   length 属性, 字符串的长度  length()  方法
        //  集合中元素的个数  size() 方法
        System.out.println(collection.size());

        //collection.clear();
        Collection collection3 = null;
        // 会报错,空指针异常
        // System.out.println(collection3.isEmpty());

        // 将一个集合转换为数组
        Object[] objects = collection.toArray();




    }
}

3、集合的循环遍历

1) 使用迭代器

package com.qfedu.day10_2;

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

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/14 11:35
 * @Version 1.0
 */
public class DemoIterator {

    public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add("泰坦尼克号"); // 昨日重现
        collection.add("功夫"); //
        collection.add("怦然心动"); //

        // 获取迭代器  iterator
        Iterator iterator = collection.iterator();
        // 使用迭代器中的方法
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }

        /**
         * Exception in thread "main" java.util.NoSuchElementException
         *     at java.util.ArrayList$Itr.next(ArrayList.java:854)
         *     at com.qfedu.day10_2.DemoIterator.main(DemoIterator.java:28)
         */
        //System.out.println(iterator.next());
        /*if(iterator.hasNext()){

        }*/
    }
}

2) 使用for循环

package com.qfedu.day10_2;

import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/14 11:41
 * @Version 1.0
 */
public class DemoFor {
    public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add("泰坦尼克号"); // 昨日重现
        collection.add("功夫"); //
        collection.add("怦然心动");
        /*// 增强for循环,非常的常用
        for (Object o : collection) {
            System.out.println(o);
        }*/

        /**
         *  jdk1.8 以后出现的,不常用,平常使用上面的for 增强版
         */
        collection.forEach(new Consumer() {
            @Override
            public void accept(Object o) {
                System.out.println(o);
            }
        });

        // System.out.println
        collection.forEach(o -> System.out.println(o));
        //  // System.out.println  -->  System.out::println
        // 每次从集合中拿出一个元素,然后打印
        //collection.forEach(System.out::println);

    }
}

三、List集合

1、需要了解的概念:
学好了之后可以替换数组,底层也使用的数组。
List是一个接口,是Collection 的子接口,ArrayList 是里面非常重要的一个实现。
2、常用方法(重点)
Collection 中的方法,在List中都可以使用。

package com.qfedu.day10_3;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.function.UnaryOperator;

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/14 14:45
 * @Version 1.0
 */
public class DemoList {

    public static void main(String[] args) {
        /**
         *   如果不写泛型,那么默认的泛型就是Object 类
         */
        List list = new ArrayList<>();
        list.add("java");// String
        list.add(true); // Boolean
        list.add(100); // Integer

        /**
         *   定义的时候写了具体的类当泛型,那么就约束了此集合中只能存放某个类型,其他不能存放
         *   泛型其实就是:约束
         */
        List<String> list2 = new ArrayList<String>();
        // 添加一个元素
        list2.add("java");// String
        list2.add("scala");// String
        list2.add("spark");// String

        System.out.println(list2);
        // add 在某个下标出,添加一个元素,后面的元素,自动往后移
        list2.add(1,"hadoop");
        System.out.println(list2);

        List<String> list3 = new ArrayList<String>();
        list3.add("豆豆三部曲");
        list3.add("西游记");

        // addAll 在集合中的某个位置,添加另一个集合,其他元素后移
        list2.addAll(1,list3);
        System.out.println(list2);

        //  get(下标)  获取该下标出的元素
        System.out.println(list2.get(0));
        //   set(下标,新的元素)  通过下标修改元素,返回老的元素内容
        String old = list2.set(0, "hive");
        System.out.println(old);
        System.out.println(list2);

        // 通过内容删除元素,返回boolean类型
        list2.remove("豆豆三部曲");
        // 根据下标删除,返回值是在该下标上的元素。
        System.out.println(list2.remove(1));

        System.out.println(list2);
        for (String str:list2) {
            System.out.println(str);
        }

        for (int i = 0; i < list2.size(); i++) {
            System.out.println(list2.get(i));
        }

        // hive在 list2 中的下标是多少,如果没有,返回  -1
        // 都是指的是第一次出现的下标位置
        System.out.println(list2.indexOf("hive"));
        System.out.println(list2.lastIndexOf("hive"));
        System.out.println(list2.contains("hive"));

        // 截取 list集合中一部分作为另一个list集合,前包后不包
        List<String> sub = list2.subList(0, 2);
        System.out.println(sub);

        // list2.sort(此处需要一个比较器才行);
        System.out.println();
        list2.replaceAll(new UnaryOperator<String>() {
            @Override
            public String apply(String s) {
                return s.toUpperCase();
            }
        });

        list2.replaceAll(s -> s.toUpperCase());

        System.out.println(list2);

        //  [hive, hadoop, scala, spark]

        list2.sort(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.length() - o2.length();
            }
        });

        list2.sort(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                // String 通过字典顺序进行排序
                /*
                      return   -1  升续的
                                0   表示两者相等了
                               +1  降续
                 */
                // return o1.compareTo(o2);
                return o2.compareTo(o1);
            }
        });

        list2.sort((o1,o2) -> o2.compareTo(o1));

        System.out.println(list2);

        //   如果是user 列表,需要排序,那么就需要实现比较器进行比较,具体是按照什么比较,需要根据业务来。
        //   List<User>  list =new ArrayList<User>();

    }
}

3、两种比较器的用法,详见其他文档即代码

package com.qfedu.day10_4;

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/14 15:55
 * @Version 1.0
 */
public class Person /*implements Comparable<Person>*/{

    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    /**
     *  编写比较规则
     * @param o
     * @return
     */
    /*@Override
    public int compareTo(Person o) {
        return this.age - o.age;
    }*/


    /*@Override
    public int compareTo(Object o) {
        return 0;
    }*/
}
package com.qfedu.day10_4;

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

/**
 * @Author laoyan
 * @Description TODO
 * @Date 2022/3/14 15:54
 * @Version 1.0
 *
 *
 *   我们知道,一组int类型的数据,可以通过Arrays.sort()进行排序,而如果是其他类型的数据呢?比如一个对象,那么如何用Arrays.sort()来排序呢?
 * 下面我们以对Person的Age来进行排序,age小的在前面
 *
 *    Comparable   Compartor
 *    1) 都是接口,都是函数式接口
 *    2) 都是用来比较的,常用于 引用数据类型的比较,只需要编写比较规则即可
 *    3)  Comparable 里面的方法
 *           public int compareTo(Person o) {
 *         return this.age - o.age;
 *         }
 *        Compartor 里面的方法:
 *        public int compare(Person o1, Person o2) {
 *                 return o1.getAge() - o2.getAge();
 *        }
 *    4)  推荐使用比较器,因为它类似于一个插件,插拔模式,用之即来,挥之即去,侵入性非常小。
 *
 */
public class Demo01 {

    public static void main(String[] args) {
        int[] arr = {10,8,23,35,9};
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));

        Person[] arr2 = new Person[4];// null,null,null,null
        arr2[0] = new Person("zhangsan",23);
        arr2[1] = new Person("lisi",18);
        arr2[2] = new Person("wangwu",25);
        arr2[3] = new Person("zhaoliu",19);

        //  com.qfedu.day10_4.Person cannot be cast to java.lang.Comparable
        //  Person 类,没有实现 Comparable 的接口
        //Arrays.sort(arr2);
        Arrays.sort(arr2, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge() - o2.getAge();
            }
        });
        System.out.println(Arrays.toString(arr2));
    }
}

4、ArrayList中的扩容规则

1、new ArrayList()   --> 底层使用了数组,数组长度为0
2、add 方法      -->  add 方法就是将元素添加到数组中的过程,每次添加的时候都要判断数组是否满了。
        刚开始调用这个方法的时候,需要初始化长度   10 个长度的数组
   每次扩容都是之前的1.5倍   10 -->  15  -->  22.5(22)
3、底层使用Object[]  数组。
// 初始化一个长度为1000000长度的容量,防止出现大量的数组倍扩容创建复制的过程,提高效率。
        // 必须提前预估出来大概有多少数据。
        ArrayList<String> arrayList = new ArrayList<>(1000000);

5、泛型(了解) 先定义后使用
1) 可以写在类上 class Tools {
E part;
}

  2)  可以使用在接口上<br />         interfafce  Tools <E> {<br />              E  getPart();<br />       }<br />       3)  方法上可以用:   一般跟类上的照应, 如果想使用其他的泛型,类上没有,需要在方法的前面定义,再使用
public <F>  void  show(F f){
        ArrayList<F> list = new ArrayList();
    }
    4)  ?  代表任意一种数据类型
Class<?> class1 = Object.class;
     5)   泛型的上下限<br />     上限:<br />       比如我们看到了一个 类      class   Tools <?  extends E> {

 }
 Tools tools = new Tools<Person>()

    toools里面可以存放 Person 的实例化对象以及他的子类
下限:    class Tools <?  super E> {<br />    }
 Tools tools = new Tools<Student>()

    toools里面可以存放 Student 的实例化对象以及他的父类,子类是无法使用的。