一、lambda表达式
1、概念
lambda表达式, 是Java8的一个新特性, 也是Java8中最值得学习的新特性之一。
lambda表达式, 从本质来讲, 是一个匿名函数。 可以使用这个匿名函数, 实现接口中的方法。 对接口进行非常简洁的实现, 从而简化代码。
2、初识
package com.qfedu.day10;
/**
* @Author laoyan
* @Description TODO
* @Date 2022/3/14 9:07
* @Version 1.0
*/
public interface SingleReturnSingleParameter {
int test(int a);
}
package com.qfedu.day10;
/**
* @Author laoyan
* @Description TODO
* @Date 2022/3/14 9:09
* @Version 1.0
*/
/**
* 某个接口,之前如果想调用的话,必须实现该接口
*/
public class SingleReturnSingleParameterImpl implements SingleReturnSingleParameter{
@Override
public int test(int a) {
return a * a;
}
}
可以简化为:
package com.qfedu.day10;
/**
* @Author laoyan
* @Description TODO
* @Date 2022/3/14 9:10
* @Version 1.0
*/
public class MainTest {
public static void main(String[] args) {
/**
* 第一种写法
*/
SingleReturnSingleParameter singleReturnSingleParameter = new SingleReturnSingleParameterImpl();
int test = singleReturnSingleParameter.test(10);
System.out.println(test);
/**
* 接口new了
* 如果我们为了调用某个接口,而去实现这个类,其实这个类叫什么名字已经不重要了,而是具体的实现代码
*
* 以下是使用了匿名类,匿名类就是没有名字的类,因为叫什么不重要。
*
* lambda表达: 直接复制小口号 ,写死右箭头, 复制大括号即可
*
* -> 为什么呢 λ 简化为 ->
*/
SingleReturnSingleParameter singleReturnSingleParameter1 = new SingleReturnSingleParameter() {
@Override
public int test(int a) {
return a*a;
}
};
/**
* 通过lambda表达式简化以上代码
*/
SingleReturnSingleParameter singleReturnSingleParameter2 = (int a) -> {
return a*a;
};
SingleReturnSingleParameter singleReturnSingleParameter3 = (a) -> {
return a*a;
};
SingleReturnSingleParameter singleReturnSingleParameter4 = a -> a*a;
}
}
3、认真讲解lambda表达式
1)适用场景
虽然说, lambda表达式可以在一定程度上简化接口的实现。 但是, 并不是所有的接口都可以使用lambda表达式来简洁实现的。
lambda表达式毕竟只是一个匿名方法。 当实现的接口中的方法过多或者过少的时候, lambda表达式都是不适用的。
lambda表达式,只能实现函数式接口。
只能针对函数式接口,所谓的函数式接口就是一个接口中,只能有一个未实现的方法。
记住: 接口中有且仅有一个方法必须实现,称之为函数式接口
// 这个接口中, 有且只有一个方法, 是实现类必须实现的, 因此是一个函数式接口
interface Test1 {
void test();
}
// 这个接口中, 实现类必须要实现的方法, 有两个! 因此不是一个函数式接口
interface Test2 {
void test1();
void test2();
}
// 这个接口中, 实现类必须要实现的方法, 有零个! 因此不是一个函数式接口
interface Test3 {
}
// 这个接口中, 虽然没有定义任何的方法, 但是可以从父接口中继承到一个抽象方法的。 是一个函数式接口
interface Test4 extends Test1 {
}
// 这个接口, 虽然里面定义了两个方法, 但是defualt方法子类不是必须实现的。
// 因此, 实现类实现这个接口的时候, 必须实现的方法只有一个! 是一个函数式接口。
interface Test5 {
void test5();
default void test() {}
}
// 这个接口中的 toString 方法, 是Object类中定义的方法。
// 此时, 实现类在实现接口的时候, toString可以不重写的! 因为可以从父类Object中继承到!
// 此时, 实现类在实现接口的时候, 有且只有一个方法是必须要重写的。 是一个函数式接口!
interface Test6 {
void test6();
String toString();
}
class A implements Test6{
// 此处必须实现的方法只有一个,test6() ,toString() 可以选择性实现。
}
2)快速判定一个接口是不是函数式接口的方法:
@FunctionalInterface
这个注解,在接口上一放,只要不报错,就说明该接口是函数式接口。
@FunctionalInterface
public interface AInterafce {
int test1();
String toString();
}
我们的java中有一个叫做JUC的包—>java.util.concurrent 里面大量使用着函数式接口。
3) 语法
(参数) -> {
方法体
};
就是先复制方法的参数,小括号里面有什么就复制什么,紧跟一个拉姆达 -> ,后面使用大括号编写需要实现的内容即可。
这个是最标准的写法,在这个基础上可以进行简化。
口诀: 拷贝小括号,写死右箭头,落地大括号
4) 案例
根据函数式接口中,唯一的方法 有没有参数,有没有返回值,可以组合为多种情况:
/**
* @Author 千锋大数据教学团队
* @Company 千锋好程序员大数据
* @Date 2020/4/8
* @Description
*/
interface NoneReturnNoneParameter{
// 因为接口中的方法,根据返回值的类型以及参数类型,排列组合可以分为很多种情况
void test();
}
public class Syntax {
public static void main(String[] args) {
// 1. 无参、无返回值的方法实现
NoneReturnNoneParameter lambda1 = () -> {
System.out.println("无参、无返回值方法的实现");
};
lambda1.test();
// 2. 有参、无返回值的方法实现
NoneReturnSingleParameter lambda2 = (int a) -> {
System.out.println("一个参数、无返回值方法的实现: 参数是 " + a);
};
lambda2.test(10);
// 3. 多个参数、无返回值方法的实现
NoneReturnMutipleParameter lambda3 = (int a, int b) -> {
System.out.println("多个参数、无返回值方法的实现: 参数a是 " + a + ", 参数b是 " + b);
};
lambda3.test(10, 20);
// 4. 无参、有返回值的方法的实现
SingleReturnNoneParameter lambda4 = () -> {
System.out.println("无参、有返回值方法的实现");
return 666;
};
System.out.println(lambda4.test());
// 5. 一个参数、有返回值的方法实现
SingleReturnSingleParameter lambda5 = (int a) -> {
System.out.println("一个参数、有返回值的方法实现: 参数是 " + a);
return a * a;
};
System.out.println(lambda5.test(9));
// 6. 多个参数、有返回值的方法实现
SingleReturnMutipleParameter lambda6 = (int a, int b) -> {
System.out.println("多个参数、有返回值的方法实现: 参数a是 " + a + ", 参数b是 " + b);
return a * b;
};
System.out.println(lambda6.test(10, 20));
}
}
5) lambda 表达式有进一步简化的空间
1、参数可以简化
1)省略参数类型 (int a) 可以写成 (a)
// 多个参数、无返回值的方法实现
NoneReturnMutipleParameter lambda1 = ( a, b) -> {
System.out.println("多个参数、无返回值方法的实现: 参数a是 " + a + ", 参数b是 " + b);
};
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、集合的整体印象
通过以上这个图,我们可以得到什么?
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 的实例化对象以及他的父类,子类是无法使用的。