# 集合 Lambda表达式
适合做服务器开发:JAVA .net pht c++ c# asp golang python…
前端:ios android H5 jsp…
数据库:mysql oracle BD2 Hbase MonggoDB redis ,sql sever…
大数据:hadoop flume spark hive yarn zonokeeprer kafka sqoop,HDFS mr,scala…
只有一个抽象方法的接口,java8的新特性,java可以函数式编程,在并发性能上迈出了实质性的一步。
1. 匿名内部类可以为任意接口创建实例,不管接口包含多少个抽象方法,只要匿名内部类实现所有的抽象方法即可; 但Lambda表达式只能为函数式接口创建实例(即只能有一个抽象方法)
2. 匿名内部类可以为抽象类甚至是普通类创建实例;但Lambda表达式只能为函数式接口创建实例
3. 匿名内部类实现的抽象方法的方法体允许调用接口中定义的默认(default)方法;但Lambda表达式的代码块不允许调用接口中的默认(default)方法
1.构成:(参数)->表达式 or (参数)->{方法体;}
2.形参列表:形参列表允许省略形参类型,若形参列表中只有一个参数,形参列表的圆括号也可以省略代码
3.箭头(->):必须通过英文的划线号和大于符号组成
4.代码块:如果代码块只包含一条语句,lambda表达式允许省略代码块的花括号,那么这条语句就不要用花括号表示语句结束
5.返回值:lambda代码块只有一条return语句,甚至可以省略return关键字。(lambda表达式需要返回值,而它的代码块中仅有一条省略了return的语句,lambda表达式会自动返回这条语句的结果)
6.lambda表达式可以直接作为函数的参数,当要实现只有一个接口的抽象函数时,使用lambda表达式能够更灵活。
7.lambda表达式类型:它的定义是:一个接口,如果只有一个显式声明的抽象方法,那么它就是一个函数接口。一般用@FunctionalInterface标注出来 (也可以不标记),函数式接口可以
包含多个default或static方法,但是只能声明一个抽象方法。(注解)@FuctionalInterface主要作用就是检查当前接口是不是函数接口。
8.如果是全局的变量直接用.如果是局部变量会被默认在前面添加final(被作为常量,类似于局部变量在局部内部类中使用的情况)
1.引用类方法
//* 1.引用类方法
interface Converter{
//将字符串转换成整数
Integer convert(String value);
}
class Test1{
public static void fun1() {
//原来的方法
Converter converter = value->Integer.valueOf(value);
Integer v1 = converter.convert("222");
System.out.println(v1);
//简化
//引用类方法
//通过::实现,这里会自动将lambda表达式方法的参数全部传递给当前的方法
Converter converter2 = Integer::valueOf;
Integer v2 = converter2.convert("333");
System.out.println(v2);
}
}
2.引用特定对象的实例方法
//* 2.引用特定对象的实例方法
interface IA{
public void show(String message);
}
class A{
public void play(String i) {
System.out.println("这里是A的方法play"+" i:"+i);
}
}
class Test2{
public static void fun2() {
//原来
IA ia = message->new A().play(message);
ia.show("hello");
//简化
IA ia2 = new A()::play;
ia2.show("world");
}
}
3.引用某类对象的实例方法
//* 3.引用某类对象的实例方法
interface IB{
String subString(String string,int stat,int end);
}
class Test3{
public static void fun3() {
//原来
IB ib = (string,stat,end)->string.substring(stat, end);
String sub1 = ib.subString("hello world", 2, 4);
System.out.println(sub1);
//简化
//函数式接口中被实现方法的第一个参数作为调用者,后面的参数全部传递给该方法
IB ib2 = String::substring;
String sub2 = ib2.subString("class is over", 2, 5);
System.out.println(sub2);
}
}
4.引用构造
interface IC{
Object show(String name,int age);
}
class Person{
String name;
int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
class Test4{
public static void fun4() {
IC ic = (name,age)->new Person(name, age);
Object per = ic.show("bing", 19);
System.out.println(per);
//简化
//构造方法引用代替lambda表达式,函数式接口中被实现方法的全部参数传该构造方法作为参数
IC ic2 = Person::new;
Object per1 = ic2.show("chen", 10);
System.out.println(per1);
}
}
集合可以存储引用数据类型,可以存储不同的数据类型。
1.数组:可以存储不同类型的多个数据,数据类型可以是简单数据类型可以是引用数据类型。
缺点:创建的是一个定值,只能存储固定长度的数据,一旦存满了,就不能再继续存储
2.集合:可以存储不同类型的多个数据,但只能存储引用数据类型
缺点:只能存储引用数据类型
优点:存储空间会随存储数据的增大而增大。合理利用内存空间
- Collection:-----接口
list – -接口
ArrayList—类
Vector------类
LinKedList–类
Set------接口
HasSet------类
TreeSet-----类
- Map:–接口
hashMap-- 类
TreeSet–类
方法:
1. 添加:collection.add(“java”);
2. 删除:boolean remove(Object o);void clear() clear !=null//clear()完还可以存数据
3. 判断:boolean contains(Object o) // 底层用的是equals,是Object o调用的equals
4. 判断:boolean isEmpty() //判断集合是否为空 空 != null
5. 集合变数组:集合变数组:当不希望别人改变集合长度的时候.Object[] objects = collection.toArray();
遍历:当集合中同时存在不同类型的数据时,需要进行容错处理和向下转型.
1.迭代器遍历:
hasnext():判断当前位置是否有元素,有就返回TRUE,没有就返回false
next();将当前位置的值取出,并且将指针后移一个位置。
**获取迭代器:1.创建对象 2.与集合绑定
Iterator iterator()//获取集合中的对象
代码示例:
while (iterator1.hasNext()) {
Object object = iterator1.next();//多态
if (object instanceof String) { //容错处理
System.out.println(“iterator2:”+object);
}
}
2.枚举器遍历:
Enumeration enumeration = vector.elements();
while (enumeration.hasMoreElements()) {
Object object = (Object) enumeration.nextElement();
System.out.println(object);
}
1.List:存取的数据是有序的(元素的存储顺序与添加元素的顺序一致),可以重复的
ArrayList;底层是的数据结构是数组,线程安全,特点:查找速度快,添加删除速度慢,
Vector:底层的数据结构是数组,线程安全的.特点:查找速度快,添加删除速度慢
LinkedList:底层是链表,线程不安全的.特点:查找速度慢,添加删除速度快.
2.Set:存储的数据类型无序的,不可重复。
1.增:
void add(int index, E element)
boolean addAll()
2.删
E remove(int index) //返回删除的元素
3.修改
E set(int index, E element)
4.查找 (迭代器) 可以并发修改:在遍历的时候在增加元素
ListIterator listIteator(int index)
public static void test(List list) {
//先获取迭代器对象
ListIterator listIterator = list.listIterator();
//从左到右
while (listIterator.hasNext()) {
String object = (String) listIterator.next();
System.out.println("从左到右:"+object);
}
//从右到左
while (listIterator.hasPrevious()) {
String object = (String)listIterator.previous();
System.out.println("从右到左:"+object);
}
//内部有add,set,remove方法,可以直接对当前位置的元素进行操作
//从左到右
while (listIterator.hasNext()) {
String object = (String) listIterator.next();
if (object.equals("haha")) {
//在使用迭代器期间,使用list的删除方法直接删除元素,有可能发生错误,所以不要这样做
//list.remove(object);
//使用迭代器自带的remove方法
//用迭代器提供的方法,注意:remove,add,set不要同时使用
listIterator.remove();
}
System.out.println("从左到右:"+object);
}
}
在使用迭代器期间,使用list的删除方法直接删除元素,有可能发生错误,所以不要这样做
1.遍历的时候用的是枚举器;
Enumeration enumeration = vector.elements();
while(enumeration.hasMoreElements()){
Object object = (Object) enumeration.nextElement();
System.out.println(object);
}
1.addFirst();从为首添加
2.addLast();从末尾添加
3.getFirst();
4.removeFirst()
5.removeLast()
从JDK1.6开始出现:
1.offerFirst() //存值
2.offerLast()
3.peekFirst()//获取对象不存在的时候会返回NULL
4.peekLast()
5.pollFirst()//删除的对象不存在会返回NULL
6.pollLast()
1. HashSet:底层是哈希表,线程不安全
2. TreeSet:底层是二叉树,线程不安全
1. 原理:通过调用元素的hashCode和equals方法去实现去重,首先调用hashCode方法,拿到当前对象的哈希码值,去让两个对象的哈希码值进行比较,如果不同,直接认为是两个对象,不在去调用equals,如果继续调用equals方法,返回true认为是一个对象,反之则认为是2个对象。
2. 先调用hashCode再调equals,
问题:为什么要重写hashCode()?为了去重复
实现Comparable接口:自然排序
1. TreeSet的add方法实现了排序,去重,通过调用元素的CompareTo方法(String 已经实现了CompareTo接口)
2. 没有实现Compareble接口的对象不能当做TreeSet的元素,否则报异常ClassCastException
3. CompareTo 返回 0只有一个元素;返回 1 怎么存怎么取;-1倒序
4. 实例代码:
@Override
public int compareTo(Object o) {
//根据自己制定的规则比较
//根据年龄和姓名比较
//容错处理
if (!(o instanceof Person2)) {
throw new ClassCastException("类型转换错误");
}
//向下转型
Person2 person2 = (Person2)o;
//先比姓名
int num = this.name.compareTo(person2.name);//String 已经实现了CompareTO,
//再按照年龄比
return num==0?this.age-person2.age:num;
}
Comparator接口:人工排序
步骤:
1. 创建一个比较器类:实现了 Comparator
lass ComStrWithLength implements Comparator{
@Override
public int compare(Object o1, Object o2) {
//比较字符串的长度
if (!(o1 instanceof String)) {
throw new ClassCastException("类型转换错误");
}
if (!(o2 instanceof String)) {
throw new ClassCastException("类型转换错误");
}
//向下转型
String s1 = (String)o1;
String s2 = (String)o2;
//先按照长度比
int num = s1.length()-s2.length();
//长度相同,再按照字典顺序比
return num==0?s1.compareTo(s2):num;
}
}
2. 创建比较器对象:
ComStrWithLength comStrWithLength = new ComStrWithLength();
3. 将比较器对象交给TreeSet:
Set set = new TreeSet<>(comStrWithLength);
注意:人工排序的优先级高于默认排序
1.本来集合是可以存任何引用类型,但是如果在后期的话,还得容错处理,向下转型。泛型是为了解决上面的问题,让你清楚的知道,集合里面存的是什么。
2.把错误检测从运行阶段,调到了编译阶段。提高安全性和效率。
原理:之前add()的返回值是object,在加了后,add()的返回值为String
注意:泛型使用:类,方法,接口
1. 相当于定义了一种类型。当泛型类型确定之后,类型就确定了
1.在类上使用泛型
class Student1{
E tools;
public E getTools() {
return tools;
}
public void setTools(E tools) {
this.tools = tools;
}
}
2.方法上使用泛型:泛型在使用时可以一次定义多个.之间使用,隔开
1. 方法上的泛型与类上的泛型保持一致
class Dog{
//1.方法上的泛型与类上的泛型保持一致
public void eat(F f) {
System.out.println(f);
}
}
2. 方法上独立使用泛型:注意:泛型在使用之前一定要先进行定义,定义的方式:在当前方法的最前面添加<泛型>,作用:让方法与方法内的泛型保持一致
public void song(E e) {
ArrayList arrayList = new ArrayList<>();
System.out.println(e);
}
3. 静态方法上使用泛型:必须独立使用,方式:在static 后面定义泛型 <泛型>
public static
3.接口上使用泛型:我们主要研究的是实现接口的子类上的泛型是如何使用的
1. 子类上的泛型与接口上的一致:类上的泛型确定了,接口上的泛型就确定了,方法上的泛型就确定了
2. 接口上使用泛型,子类上不用泛型:在实现的接口位置必须指定一个具体的泛型
interface Inte{
public void show(E e);
}
//1.子类上的泛型与接口上的一致
/* 类上的泛型确定了,接口上的泛型就确定了,方法上的泛型就确定了
*/
class Pig implements Inte{
@Override
public void show(E e) {
System.out.println(e);
}
}
//2.接口上使用泛型,子类上不用泛型
/*在实现的接口位置必须指定一个具体的泛型
*
* 方法使用泛型的情况:
* 1.如果是重写的方法,泛型与接口一致
* 2.如果是子类自己的方法,可以与接口一致,也可以有自己的泛型
*/
class Bird implements Inte{
public void show(String e) {};
}
### 限制上限 和限制下线
/*
* 关于java中?的使用
1)用于?: 这里是算目运算符一部分,前面是判断条件,后面是两个分支结果
2)用于数据库的sql语句 select * from emp where name=? :表示占位符
3)用于泛型,表示任意一种数据类型.
//这里的Object与前面的?没有关系
Class> class1 = Object.class;
//如果类的泛型使用时写成?是可以的.作为返回值时,会默认成Object类型,但是作为参数不行.所以在给对象指定泛型时要写具体类型
Test> test = new Test();
//test.run(new Object());
class Test{
T e;
public T run(T a) {
T t = null;
return t;
}
}
*/
/*
* 了解:
*
* ?:通配符,可以表示一种或几种数据类型
* 限制上限: extends E>:限制的是整个的<>可以取的泛型类型的上限是E,<>中可以取的类型是E及E的子类
* 限制下限: super E>::限制的是整个的<>可以取的泛型类型的下限是E,<>中可以取的类型是E及E的父类
*
*
* 讲的是限制上限: extends E>
*/
public class Demo14
{
public static void main(String[] args) {
//
ArrayList list1 = new ArrayList<>();
list1.add(new Student2("bingbing", 1));
//可以传参:因为Student2是Person1的子类,可以实现遍历
bianli(list1);
ArrayList list2 = new ArrayList<>();
list2.add(new Teacher("bingbing", 1));
//可以传参:因为Teacher1是Person1的子类,可以实现遍历
bianli(list2);
ArrayList list3 = new ArrayList<>();
list3.add(new Person4("bingbing", 1));
//可以传参
bianli(list3);
ArrayList