一、Lambda表达式
Lambda是JAVA 8添加的新特性,可以看成是一个匿名函数
使用Lambda表达式可以对一个接口的方法进行非常简洁的实现
要求接口中定义的必须要实现的抽象方法只能是一个
可以使用default对接口方法进行修饰,被修饰的方法在接口中可以默认实现
@FunctionalInterface
修饰函数式接口的,接口中的抽象方法只有一个
|
|
二、lambda表达式的基础语法
(参数列表)->表达式,例如(k1,k2)-> k1+k2
(参数列表)->{代码块;},例如(k1,k2)->{return k1+k2;}
()参数列表
{} 方法体
-> lambda运算符,读作goes to
public class Test02 {
public static void main(String[] args) {
// 无参无返回
LambdaNoneReturnNonParameter lambda1 = () -> {
System.out.println("hello world");
};
lambda1.test();
// 单参无返回
LambdaNoneReturnSingleParameter lambda2 = (int a) -> {
System.out.println(a);
};
lambda2.test(10);
// 多参无返回
LambdaNoneReturnMutipleParameter lambda3 = (int a, int b) -> {
System.out.println(a + b);
};
lambda3.test(5, 6);
// 无参有返回
LambdaSingleReturnNoneParameter lambda4 = () -> {
return -1;
};
int res1 = lambda4.test();
System.out.println(res1);
// 单参有返回
LambdaSindleReturnSingleParameter lambda5 = (int a) -> {
return a + 1;
};
int res2 = lambda5.test(2);
System.out.println(res2);
// 多参数有返回
LambdaSindleReturnMutipleParameter lambda6 = (int a, int b) -> {
return a + b;
};
int res3 = lambda6.test(5, 6);
System.out.println(res3);
}
}
interface LambdaNoneReturnSingleParameter {// 无返回单参数
void test(int n);
}
interface LambdaNoneReturnNonParameter {// 无返无参的接口
void test();
}
interface LambdaNoneReturnMutipleParameter {// 无返回多参数
void test(int a, int b);
}
interface LambdaSingleReturnNoneParameter {// 有返回无参
int test();
}
interface LambdaSindleReturnSingleParameter {// 有返回单参
int test(int a);
}
interface LambdaSindleReturnMutipleParameter {// 多参数有返回
int test(int a, int b);
}
三,语法精简
1.参数类型:
由于在接口的抽象方法中,已经定义了参数的数量类型 所以在Lambda表达式中参数的类型可以 省略。备注:如果需要省略类型,则每一个参数的类型都要省略。
2.参数小括号:
如果参数列表中,参数的数量只有一个 此时小括号可以省略。
3.方法大括号:
如果方法体中只有一条语句,此时大括号可以省略
4.如果方法体中唯一的一条语句是一个返回语句:
省略大括号的同时 也必须省略return。
//1.参数类型:可以省略,必须都省略
LambdaNoneReturnMutipleParameter lambda1 = (a,b)->{
System.out.println("hello world");
};
//2.参数只有一个小括号可以省略
LambdaNoneReturnSingleParameter lambda2 = a->{
System.out.println("hello world");
};
//3.方法大括号,方法体只有一条语句大括号可以省略
LambdaNoneReturnSingleParameter lambda3 = a->System.out.println("hello world");
//4.方法体中只有一个返回语句,省略大括号同时省略return;
LambdaSingleReturnNoneParameter lambda4 = ()->5;
四,方法引用:
1.普通方法引用
可以快速的将一个Lambda表达式的实现指向一个已经实现的方法。
方法的隶属者 如果是静态方法 隶属的就是一个类 其他的话就是隶属对象。
语法:方法的隶属者::方法名
注意:
1.引用的方法中,参数数量和类型一定要和接口中定义的方法一致
2.返回值的类型也一定要和接口中的方法一致
public static void main(String[] args) {
LambdaSindleReturnSingleParameter lambda1 = a->a*2;
//简化
LambdaSindleReturnSingleParameter lambda1 = a->change(a);
//方法引用:引用change方法的实现
LambdaSindleReturnSingleParameter lambda2 = Test3::change;
}
public static int change(int a) {
return a*2;
}
2、构造方法的引用
public static void main(String[] args) {
PersonCreater creater = ()-> new Person();
//构造方法的引用
PersonCreater creater1 = Person::new;
Person a = creater1.getPerson();
PersonCreater2 creater2 = Person::new;
Person b=creater2.getPerson("张三", 18);
}
}
class Person{
private String name;
private int age;
public Person() {
System.out.println("Person类的无参构造方法执行了");
}
public Person(String name,int age) {
this.name=name;
this.age=age;
System.out.println("Person类的有参构造方法执行了");
}
}
interface PersonCreater{
Person getPerson();
}
interface PersonCreater2{
Person getPerson(String name,int age);
}
五、系统内置的4大函数式接口
Consumer消费性接口void accept(T t)
Supplier供给性接口T get()
Function函数式接口R apply(T t)
Predicate断言式接口boolean test(T t)
set集合
Set是Collection接口的子接口,特点:无序、不允许重复【hashcode和equals】,没有定义新方法,当添加的两个对象类型元素的hashCode值相等时,才会调用equals判定相等,如果hashCode值不相等,则不会调用equals方法
特征:
允许使用null元素
没有新方法,对add、equals和hashCode方法添加了限制
具体实现类有HashSet、LinkedHashSet和TreeSet
Set–>HashSet–>LinkedHashSet
SortedSet –> TreeSet
HashSet类
HashSet实现了Set接口,底层实际上是包装了一个HashMap实现的
HashSet采用hash算法来存储集合中的元素,因此具有良好的读写性能
调用add方法向HashSet中添加元素时,首先是针对对象的hashcode值进行比较。如果两个对象的hashcode值相等时才会继续调用equals方法;如果两个对象的hashcode值不相等,则不会调用equals方法
要求:定义类时如果equals为true,则hashcode值必须相等;但是hashcode值相等不一定equals为true。
散列算法
散列算法hashing是一种将字符构成的字符串转换为固定长度的数值或者索引值的方法,称为散列法或者哈希法,由于通过更短的哈希值进行比较比使用原始值仅从比较速度快,一般用来在数据库中建立索引并进行搜索,同时也可以用于在各种加密解密算法中
Java中的所有类都可以从Object类中继承得到了hashCode方法的实现,同时允许覆盖定义,但是Object类中继承得到的hashCode方法返回的是一个和当前对象存储地址相关的int型值,所以new两个对象的hash值不相等
String类中的hashcode方法的实现
private char [] value ; // 字符串的存储实际上是采用char[]数组实现的
private int hash; // 当前字符串对象中会缓存一个hash值,默认值为0
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) { // 如果缓存的hash值为0并且char数组的长度大于0,才需要进行hash计算
char val[] = value;
for (int i = 0; i < value.length; i++) { // 遍历访问每个字符
h = 31 * h + val[i]; // 获取每个字符对应的int值,
}
hash = h; // 缓存
}
return h;
}
hashSet
的特征
无序。不仅不能保证元素的插入顺序,而且在元素以后的顺序也可能会发生变化
如果需要访问的顺序和插入的顺序一致,则可以使用HashSet的子类LinkeHashSet
存储的元素不允许重复【equals和hashcode】
强调
Set集合不允许对象重复,否则会引发各种奇怪的问题。
HashSet中需要同时通过hashCode和equals来判断两个元素是否相等,具体规则:如果两个元素通过equals判断为true,则必须两个元素的hashCode值相等。一般要求重写equals必须重写hashCode方法
HashSet判定对象重复时,首先调用对象的hashCode方法,如果两个对象的hashCode值相等时,才会调用equals进行判断,如果equals为true则两个对象重复;如果hashCode值不相等,则不会调用equals判断。如果出现对象重复,则后添加的元素直接丢弃。
HashSet方法没有同步约束,所以线程不安全
HashSet允许添加null元素。
hashset中常见方法
contains(Object):boolean 判断set中是否存在指定对象,如果存在返回为true
iterator():Iterator 迭代访问元素—-foreach写法要求必须实现Iterable接口
toArray():Object[] 放回包含所有元素的数组;如果需要指定返回数组的类型,可以使用toArray(类型[])
add(Object obj):boolean 如果set中不存在指定的元素obj,则向set中添加元素
remove(Object):boolean 删除指定元素
HashSet的底层实际上就是HashMap,只不过 HashSet是实现了Set接口,并且把数据作为key值,而具体的value值一直使用一个相同的虚值来实现的private static final Object PRESENT = new Object();由于HashMap的key值不允许重复,并且在HashMap中如果出现key值相同时,会使用新的value覆盖就有value,然后返回就有的value值,那么在hashset中执行这句话就会返回一个false,表示插入失败,这样就能保证了数据的不可重复性
LinkedHashSet
LinkedHashSet是HashSet的一个子类,LinkedHashSet也是根据hashCode值来决定元素的具体存储位置,但是同时它引入了一个链表可以维护元素的插入顺序。
底层采用链表和哈希表的算法,使用链表记录元素的添加位置,使用哈希表保证元素的唯一性