集合 Lambda表达式 详解

#  集合  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…

Lambda表达式:

只有一个抽象方法的接口,java8的新特性,java可以函数式编程,在并发性能上迈出了实质性的一步。

比较Lambda和匿名内部类(lambda是简单的匿名内部类)

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–类

ArrayList

方法:

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);

}

List set 比较

1.List:存取的数据是有序的(元素的存储顺序与添加元素的顺序一致),可以重复的

ArrayList;底层是的数据结构是数组,线程安全,特点:查找速度快,添加删除速度慢,

Vector:底层的数据结构是数组,线程安全的.特点:查找速度快,添加删除速度慢

LinkedList:底层是链表,线程不安全的.特点:查找速度慢,添加删除速度快.

2.Set:存储的数据类型无序的,不可重复。

List 常用方法:

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的删除方法直接删除元素,有可能发生错误,所以不要这样做

vector

1.遍历的时候用的是枚举器;

Enumeration enumeration  = vector.elements();

while(enumeration.hasMoreElements()){

Object object = (Object) enumeration.nextElement();

System.out.println(object);

}

LindedList

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()

Set 不可重复,无序的

1. HashSet:底层是哈希表,线程不安全

2. TreeSet:底层是二叉树,线程不安全

HashSet

1. 原理:通过调用元素的hashCode和equals方法去实现去重,首先调用hashCode方法,拿到当前对象的哈希码值,去让两个对象的哈希码值进行比较,如果不同,直接认为是两个对象,不在去调用equals,如果继续调用equals方法,返回true认为是一个对象,反之则认为是2个对象。

2. 先调用hashCode再调equals,

问题:为什么要重写hashCode()?为了去重复

TreeSet  可以实现排序和去重

实现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 void show(W w) {}

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;

        }

    }







 */



/*

 * 了解:

 * 

 * ?:通配符,可以表示一种或几种数据类型

 * 限制上限::限制的是整个的<>可以取的泛型类型的上限是E,<>中可以取的类型是E及E的子类

 * 限制下限:::限制的是整个的<>可以取的泛型类型的下限是E,<>中可以取的类型是E及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 list4 = new ArrayList<>();

        list4.add(new Object());

        //可以传参:因为Object是Person1的父类,不可以实现遍历

        //bianli(list4);

    }

    

    

    public static void bianli(Collection  e){

        System.out.println("遍历了");

    }

}



class Person4{

    String name;

    int age;

    public Person4() {

        super();

        // TODO Auto-generated constructor stub

    }

    public Person4(String name, int age) {

        super();

        this.name = name;

        this.age = age;

    }

    @Override

    public String toString() {

        return "Person4 [name=" + name + ", age=" + age + "]";

    }

}



class Teacher extends Person4{

    public  Teacher(String name, int age) {

        super(name, age);

    }

}



class Student2 extends Person4 {

    public  Student2(String name, int age) {

        super(name, age);

    }

}

 
  

                            
                        
                    
                    
                    

你可能感兴趣的:(JAVA学习之路)