四、泛型【课件内容】

121 阅读16分钟

java基础学习的文章目录

1、泛型

  • 从 Java 5 开始,增加了泛型技术
  • 什么是泛型?
    • 将类型变为参数,提高代码复用率
  • 建议的类型参数名称
    • T : Type
    • E : Element
    • K : Key
    • N : Number
    • V : Value
    • S、 U、 V : 2nd, 3rd, 4th types

泛型类型(Generic Type)

  • 什么是泛型类型?
    • 使用了泛型的类或者接口
    • 比如
      • java.util.Comparator
      • java.util.Comparable
public class Student<T> {
	private T score;

	public T getScore() {
		return score;
	}

	public void setScore(T score) {
		this.score = score;
	}
	public static void genericSample1() {
		// java7以前的写法
		// Student<String> stu1 = new Student<String>();
		
		//从java7开始,可以省略右边<>中的类型
		Student<String> stu1 = new Student<>();
		stu1.setScore("A");
		String score1 = stu1.getScore();
		System.out.println(score1); //A
		
		Student<Double> stu2 = new Student<Double>();
		stu2.setScore(98.5);
		Double score2 = stu2.getScore();
		System.out.println(score2); //98.5
	}

	public static void main(String[] args) {
		genericSample1();
	}
}

多个类型参数

public class Student2<N,S> {
	private N no;
	private S score;
	
	public Student2(N no, S score) {
		super();
		this.no = no;
		this.score = score;
	}

	public static void main(String[] args) {
		Student2<String, String> stu1 = new Student2<String, String>("E9527", "A++");
		Student2<Integer, Double> stu2 = new Student2<Integer, Double>(18, 96.5);
	}
}

2、泛型类型的继承【错误】

public class Box<E> {
	private E element;
	
	public E getElement() {
		return element;
	}

	public void setElement(E element) {
		this.element = element;
	}

	public static void main(String[] args) {
		Box<String> strBox = new Box<String>();
		Box<Integer> intBox = new Box<Integer>();
		Box<Object> objBox = new Box<Object>();
		
		strBox = intBox; // error
		//如果这个代码能正确的话,请思考下面的代码
		objBox = strBox; // error
		objBox.setElement(new Object());
		// 将Object直接转换为String?
		String str = strBox.getElement();
	}
}
  • 我们知道 Integer继承至Number
  • 但是Box 不继承Box
  • Box 是继承与Object的

泛型类型的继承【正确】

Iterable<String>
      ^
      |
Collection<String>
      ^
      |
List<String>
      ^
      |
ArrayList<String>

泛型继承的定义:

public interface Collection<E> extends Interable<E>
public interface List<E> extends Collection<E>
public class ArrayList<E> implements List<E>

正确的继承示例:

	public static void main(String[] args) {
		Iterable<String> it = null;
		Collection< String> coll = null;
		List<String> li = null;
		ArrayList<String> al = null;
		
		it = coll;
		coll = li;
		li = al;
	}

3、原始类型

  • 什么是原始类型?
    • 没有传递具体的类型给泛型的类型参数
  • 当使用了原始类型时,编译器会给出 警告(可以用 @suppressWarnings消除)
  • 将非原始类型赋值给原始类型时,编译器没有任何警告和错误
  • 将原始类型赋值给非原始类型时,编译器会给出 警告(可以用@suppressWarnings消除)
  • Box 是原始类型, Box 是非原始类型

    4、集合预览

    • java.util 包中有个集合框架(Collections Framework),提供了一大堆常用的数据结构
      • ArrayList、 LinkedList、 Queue、 Stack、 HashSet、 HashMap 等
    • 数据结构是计算机存储、组织数据的方式
      • 线性结构、树形结构、图标结构
    • 在实际应用中,根据使用场景来选择最合适的数据结构
    -----------------------接口部分-----------------------
    -----------------------Iterable-----------------------
    ----------------------collection----------------------
    Queue
    Dequeue 
            List                                       Set          Map
    -----------------------具体的类-----------------------
         LinkedList            ArrayList  Stack      HashSet      HashMap
    ------------------------抽象类-----------------------
    AbstractSequentialist                 Vector   AbstractSet  AbstractMap
    -----------------AbstractList---------------
    ------------------AbstractCollection---------------------
    
    • 思考题:为何 Map 如此独立?跟 Collection、 Iterable 毫无继承关系?

    5、ArrayList01_基本使用

    数组的局限性

    • 数组的局限性
      • 无法动态扩容
      • 操作元素的过程不够面向对象
    • ArrayList 是 Java 中的动态数组
      • 一个可以动态扩容的数组
      • 封装了各种实用的数组操作
    	public static void arrayUse() {
    		int[] array = new int[4];
    		array[0] = 11;
    		array[2] = 22;
    		//输出 [11, 0, 22, 0]
    		System.out.println(Arrays.toString(array));
    	}
    

    ArrayList的常用方法

    • int size()

    • boolean isEmpty()

    • boolean contains(Object o)

    • int indexOf(Object o)

    • int lastIndexOf(Object o)

    • E get(int index)

    • E set(int index, E element)

    • boolean add(E element)

    • boolean add(int index, E element)

    • E remove(int index)

    • boolean remove(Object o)

    • void clear()

    • boolean addAll(Collection<? extends E> c)

    • boolean addAll(int index, Collection<? extends E> c)

    • boolean removeAll(collection<?> c)

    • boolean retainAll(collection<?> c)

    • void forEach(Consumer<? supper E> action)

    • void sort(Comparator<? supper E> c)

    • Object[] toArray()

    • <T> T[] toArray(T[] a)

    • void trimToSize()

    • void ensureCapacity(int minCapacity)

    ArrayList基本使用

    	@SuppressWarnings("unchecked")
    	public static void arrayListUse() {
    		@SuppressWarnings("rawtypes")
    		ArrayList list = new ArrayList();
    		list.add(11);
    		list.add(false);
    		list.add(null);
    		list.add(3.14);
    		list.add(0, "Jack");
    		list.add("8");
    		
    		System.out.println(list.indexOf(11));//3
    		System.out.println(list.size());//6
    		System.out.println(list);//[Jack, 11, false, null, 3.14, 8]
    	}
    

    retainAll使用示例

    	public static void listRetain() {
    		List<Integer> list1 = new ArrayList<Integer>();
    		list1.add(11);
    		list1.add(22);
    		list1.add(33);
    		list1.add(44);
    		
    		List<Integer> list2 = new ArrayList<Integer>();
    		list2.add(22);
    		list2.add(44);
    		//从list1中删除list2中元素以外的所有元素
    		list1.retainAll(list2); //[22, 44]
    		System.out.println(list1);
    	}
    

    6、ArrayList02_toArray

    	public static void toArray() {
    		List<Integer> list1 = new ArrayList<Integer>();
    		list1.add(11);
    		list1.add(22);
    		list1.add(33);
    		Object[] array1 = list1.toArray();
    		System.out.println(array1);//[Ljava.lang.Object;@15db9742
    		Integer[] array2 = list1.toArray(new Integer[0]);
    		System.out.println(array2);//[Ljava.lang.Integer;@6d06d69c
    		System.out.println(Arrays.deepToString(array2));//[11, 22, 33]
    	}
    

    7、ArrayList03_遍历

    	public static void enumList() {
    		List<Integer> list = new ArrayList<Integer>();
    		list.add(11);
    		list.add(22);
    		list.add(33);
    		
    		for (int i = 0; i < list.size(); i++) {
    			System.out.println(list.get(i));
    		}
    		
    		Iterator<Integer> it = list.iterator();
    		while(it.hasNext()) {
    			System.out.println(it.next());
    		}
    		
    		for (Integer integer : list) {
    			System.out.println(integer);
    		}
    		
    		list.forEach((obj)->{
    			System.out.println(obj);
    		});
    	}
    

    for-each格式

    for(元素类型 变量名: 数组\Iterable) {
    			
    }
    
    • 实现了 Iterable 接口的对象,都可以使用 for-each 格式遍历元素
      • 比如 List、 Set 等
    • Iterable 在使用 foreach 格式遍历元素时,本质是使用了 Iterator 对象

    8、Iterable_Iterator

    public class ClassRoom implements Iterable<String>{
    	private String[] students;
    
    	public ClassRoom(String... students) {
    		super();
    		this.students = students;
    	}
    
    	@Override
    	public Iterator<String> iterator() {
    		return new ClassRoomIterator();
    	}
    	
    	private class ClassRoomIterator implements Iterator<String>  {
    		private int index;
    
    		@Override
    		public boolean hasNext() {
    			return index < students.length;
    		}
    
    		@Override
    		public String next() {
    			return students[index++];
    		}
    	}
    	
    	public static void main(String[] args) {
    		ClassRoom room = new ClassRoom("jack", "Rose");
    		for (String string : room) {
    			System.out.println(string);
    		}
    	}
    }
    

    9、ArrayList04_扩容原理

    • ArrayList 的最小容量是 10
    • 每次扩容时,新容量是旧容量的 1.5 倍

    ArrayList的内存结构

    size 
    elementData
    

    10、遍历的注意点01

    • 需求:通过遍历的方式,挨个删除所有的元素

    错误删除示例1:

    	public static void errorRemove() {
    		List<Integer> list = new ArrayList<Integer>() ;
    		list.add(11);
    		list.add(22);
    		list.add(33);
    		list.add(44);
    		list.add(55);
    		
    		//java.lang.IndexOutOfBoundsException
    		int size = list.size();
    		for (int i = 0; i < size; i++) {
    			list.remove(i);
    		}
    	}
    

    错误删除示例2:

    		// 没有删除完全
    		for (int i = 0; i < list.size(); i++) {
    			list.remove(i);
    		}
    		System.out.println(list);//[22, 44]
    

    错误删除示例3:

    		// java.util.ConcurrentModificationException
    		for (Integer integer : list) {
    			list.remove(integer);
    		}
    

    错误删除示例4:

    		// java.util.ConcurrentModificationException
    		list.forEach((e)->{
    			list.remove(e);
    		});
    
    • 如果希望在遍历元素的同时删除元素
      • 请使用 Iterator 进行遍历
      • 然后使用 Iterator 的 remove 方法删除元素

    正确的示例:

    		Iterator<Integer> it = list.iterator();
    		while (it.hasNext()) {
    			it.next();
    			it.remove();
    		}
    		System.out.println(list); //[]
    
    • 使用迭代器、 forEach 遍历集合元素时,若使用了集合自带的方法修改集合的长度(比如 add、 remove 等方法)
      • 那么会抛出 java.util.ConcurrentModificationException 异常
      • modCount++;

    11、遍历的注意点02

    • 遍历前 备份 modCount
    • 遍历的时候发现modCount改变,证明遍历的时候操作了数组

    12、ListIterator

    • ListIterator 继承自 Iterator,在 Iterator 的基础上增加了一些功能
      • boolean hasNext();
      • E next();
      • boolean hasPrevious();
      • E previsous();
      • int nextIndex();
      • int previousIndex();
      • void remove();
      • void set(E e);
      • void add(E e);

    ListIterator使用

    	public static void listsEterator() {
    		List<Integer> list = new ArrayList<Integer>() ;
    		list.add(11);
    		list.add(22);
    		list.add(33);
    		list.add(44);
    		list.add(55);
    		
    		ListIterator<Integer> it = list.listIterator();
    		while (it.hasNext()) {
    			System.out.println(it.next());
    		}
    		System.out.println("--------");
    		
    		while (it.hasPrevious()) {
    			System.out.println(it.previous());
    		}
    	}
    

    ListIterator使用示例

    	public static void listIteratorSample() {
    		List<Integer> list = new ArrayList<Integer>() ;
    		list.add(11);
    		list.add(22);
    		list.add(33);
    		ListIterator<Integer> it = list.listIterator();
    		while (it.hasNext()) {
    			it.set(it.next() + 55);
    		}
    		System.out.println(list);
    	}
    

    ListIterator使用

    	public static void listIteratorSample2() {
    		List<Integer> list = new ArrayList<Integer>() ;
    		list.add(11);
    		list.add(22);
    		list.add(33);
    		
    		ListIterator<Integer> it = list.listIterator();
    		while (it.hasNext()) {
    			it.add(77);
    			it.next();
    			it.add(77);
    		}
    		System.out.println(list);//[77, 11, 77, 77, 22, 77, 77, 33, 77]
    	}
    

    13、ArrayList05_容量相关方法

    • void trimToSize(void)
    • void ensureCapacity(int)

    14、泛型方法01

    • 什么是泛型方法?
      • 使用了泛型的方法(实例方法、静态方法、构造方法),比如 Arrays.sort(T[], Comparator<T>)
    	public static void genericMethod() {
    		Student2<String, String> s1 = new Student2<String, String>("01", "A");
    		set(s1, "02", "A+");
    		
    		Student2<Integer, Double> s2 = new Student2<Integer, Double>(3, 99.9);
    		set(s2, 4, 99.0);
    		//完整写法
    		Student2.<Integer, Double>set(s2, 5, 90.1);
    		
    		System.out.println(s2);
    	}
    
    	static <T1, T2> void set(Student2<T1, T2> stu, T1 no, T2 score) {
    		stu.setNo(no);
    		stu.setScore(score);
    	}
    

    15、泛型方法02

    泛型方法使用示例

    	public static void main(String[] args) {
    		List<Box<Integer>> boxes = new ArrayList<Box<Integer>>();
    		addBox(11, boxes);
    		addBox(22, boxes);
    		addBox(33, boxes);
    	}
    
    	public static <T> void addBox(T element, List<Box<T>> boxs) {
    		Box<T> box = new Box<T>(element);
    		boxs.add(box);
    	}
    

    返回值进行类型推断

    	public static void main(String[] args) {
    		/*
    		 public static final <T> List<T> emptyList() {
                     return (List<T>) EMPTY_LIST;
               }
    		 说明通过返回类型也能进行类型推断*/
    		List<String> list1 = Collections.emptyList();
    		List<Integer> list2 = Collections.emptyList();
    	}
    

    泛型方法-构造方法

    public class Persion<T> {
        private T age;
        public <E> Persion(E name, T age) {
            
        }
    }
    
    Persion<Integer> persion = new Persion<>("Jack", 20);
    Persion<String> persion = new Persion<>("Jack", "80后");
    
    public class Box<E> {
    	private E element;
    	
    	// 说明泛型类型E 只能用在实例方法上,和实例挂钩
    	public static void test(E element) { // error: Cannot make a static reference to the non-static type  E
    		 
    		
    	}
    }
    

    16、限制类型参数01

    • 可以通过 extends 对类型参数增加一些限制条件,比如
      • extends 后面可以跟上类名、接口名,代表 T 必须是 A 类型,或者继承、实现 A
    • 可以同时添加多个限制,比如 <T extends A & B & C>,代表 T 必须同时满足 A、 B、 C

    17、限制类型参数02

    限制类型的示例:

    public class Persion implements Comparable<Persion>{
    	private int age;
    
    	public Persion(int age) {
    		super();
    		this.age = age;
    	}
    
    	
    	@Override
    	public int compareTo(Persion o) {
    		if (o == null) {
    			return 1;
    		}
    		return age - o.age;
    	}
    
    
    	@Override
    	public String toString() {
    		return "Persion [age=" + age + "]";
    	}
    }
    
    public class Sort {
    	public static void main(String[] args) {
    		Double[] ds = {5.6, 3.4, 8.8, 4.6};
    		System.out.println(getMax(ds)); //8.8
    		
    		Integer[] is = {4,19, 3, 28, 56}; //56
    		System.out.println(getMax(is));
    		
    		Persion[] persions = {
    				new Persion(11),
    				new Persion(88),
    				new Persion(55)
    		};
    		System.out.println(getMax(persions)); //Persion [age=88]
    	}
    	
    	public static <T extends Comparable<T>> T getMax (T[] arrary) {
    		if (arrary == null || arrary.length == 0) {
    			return null;
    		}
    		T max = arrary[0];
    		for (int i = 1; i < arrary.length; i++) {
    			if (arrary[i] == null) {
    				continue;
    			}
    			if (arrary[i].compareTo(max) > 0) {
    				max = arrary[i];
    			}
    		}
    		return max;
    	}
    }
    

    18、排序01

    sort示例1:

    	public static void sort1() {
    		Persion[] persions = {
    				new Persion(11),
    				new Persion(88),
    				new Persion(55)
    		};
    		Arrays.sort(persions);
    		//[Persion [age=11], Persion [age=55], Persion [age=88]]
    		System.out.println(Arrays.deepToString(persions));
    	}
    

    从大到小的排列方式

    	public static void sort1() {
    		Persion[] persions = {
    				new Persion(11),
    				new Persion(88),
    				new Persion(55)
    		};
    		//从大到小排列
    		Arrays.sort(persions,  new Comparator<Persion>() {
    
    			@Override
    			public int compare(Persion o1, Persion o2) {
    				return o2.getAge() - o1.getAge();
    			}
    			
    		});
    		//[Persion [age=88], Persion [age=55], Persion [age=11]]
    		System.out.println(Arrays.deepToString(persions));
    	}
    

    Comparator 可以提供多种比较方式。

    • 如果数组元素本身具备可比较性(实现了java.lang.Comparable接口)
      • 可以直接使用Arrays.sort方法进行排序
    • java.util.Comparator的存在意义?
      • 可以在不修改类源代码的前提下,修改默认的比较方式(比如官方类,第三方类)
      • 可以让一个类提供多种比较方式

    19、排序02

    排序示例:

    public class ComparableStudent<T extends Comparable<T>> implements Comparable<ComparableStudent<T>>{
    	private T score;
    	public ComparableStudent(T score) {
    		super();
    		this.score = score;
    	}
    	@Override
    	public int compareTo(ComparableStudent<T> o) {
    		if (null == o) return 1 ;
    		if (score != null) return score.compareTo(o.score);
    		return o.score == null ? 0 : -1;
    	}
    	@Override
    	public String toString() {
    		return "ComparableStudent [score=" + score + "]";
    	}
    	public static void main(String[] args) {
    		ComparableStudent[] students = {
    				new ComparableStudent(11),
    				new ComparableStudent(88),
    				new ComparableStudent(55)
    		};
    		//从大到小排列
    		Arrays.sort(students);
    		//[ComparableStudent [score=11], ComparableStudent [score=55], ComparableStudent [score=88]]
    		System.out.println(Arrays.toString(students));
    	}
    }
    

    20、通配符01

    • 在泛型中,问号(?)被称为是通配符
    • 通常用作变量类型、返回值类型的类型参数
    • 不能用作泛型方法调用、泛型类型实例化、泛型类型定义的类型参数

    通配符-上界

    • 可以通过 extends 设置类型参数的上界
    public class WildCards {
    	public static void main(String[] args) {
    		Box<Integer> b1 = null;
    		Box<Number> b2 = null;
    		
    		Box<? extends Number> b3 = null;
    		Box<? extends Integer> b4 = null;
    		
    		//模糊的写法,可以赋值
    		b4 = b1; //ok
    		b4 = b2; //error
    	}
    }
    
    	public static void main(String[] args) {
    		List<Integer> is = Arrays.asList(1,2,3);
    		System.out.println(sum(is)); //6.0
    		
    		List<Double> ds = Arrays.asList(1.0,2.0,3.0);
    		System.out.println(sum(ds)); //6.0
    	}
    
    	static double sum(List<? extends Number> list) {
    		double s = 0.0;
    		for (Number n: list) {
    			s+= n.doubleValue();
    		}
    		return s;
    	}
    

    通配符下界

    • 可以通过 super 设置类型参数的下界
    • 所谓下界,必须大于等于他
    • ? super Integer 理解为类型super(超过)Integer
    void testLower(Box<? super Integer> box) {}
    Box<Integer> p1 = null;
    Box<Number> p2 = null;
    Box<? super Integer> p3 = null;
    Box<? super Number> p4 = null;
    testLower(p1);
    testLower(p2);
    testLower(p3);
    testLower(p4);
    

    下界示例代码:

    	public static void main(String[] args) {
    		List<Integer> is = new ArrayList<Integer>();
    		addNumbers(is);
    		System.out.println(is); //[0, 1, 2, 3, 4]
    		
    		List<Number> ns = new ArrayList<Number>();
    		addNumbers(ns);
    		System.out.println(ns);//[0, 1, 2, 3, 4]
    	}
    	
    	static void addNumbers(List<? super Integer> list) {
    		for (int i = 0; i < 5; i++) {
    			list.add(i);
    		}
    	}
    

    通配符-无限制

    什么都能传进去的示例:

    	public static void main(String[] args) {
    		Box<Integer> p1 = null;
    		Box<String> p2 = null;
    		Box<Object> p3 = null;
    		Box<? extends Number> p4 = null;
    		Box<? super String> p5 = null;
    		Box<?> p6 = null;
    		test3(p1);
    		test3(p2);
    		test3(p3);
    		test3(p4);
    		test3(p5);
    		test3(p6);
    	}
    	static void test3(Box<?> box) {}
    

    无限制通配符示例代码:

    	public static void main(String[] args) {
    		List<Integer> is = Arrays.asList(1,2, 3);
    		printList(is);//1 2 3 
    		
    		List<Double> ds = Arrays.asList(1.2, 2.3, 3.5);
    		printList(ds);1.2 2.3 3.5 
    	}
    	static void printList(List<?> list) {
    		for (Object object : list) {
    			System.out.print(object + " ");
    		}
    		System.out.println();
    	}
    

    21、通配符02

    通配符的继承

                      Box<?>
              ^                      ^
              |                      |
    Box<? extends Number>  Box<? super Integer> 
              ^                      ^
              |                      |
    Box<? extends Integer>  Box<? super Number> 
              ^                      ^
              |                      |
         Box<Integer>             Box<Number> 
    核心思路; 包含的范围大的是父类
    

    22、泛型的使用限制

    • 编译器在解析 List.set(int index, E element) 时,无法确定 E 的真实类型,所以报错
    	static void foo(List<?> list) {
    		Object obj = list.get(0);
    		//错误的原因:编译器在编译的时候需要确定类型,这里没有确定
    		// 假设传递的是Integer,这里这是的Object就会报错
    		list.set(0, obj); //error
    		list.set(0, list.get(0)); // error
    	}
    

    如果想编译过,用泛型方法,饶个弯:

    	static <T> void foo1(List<T> list) {
    		T obj = list.get(0);
    		//错误的原因:编译器在编译的时候需要确定类型,这里没有确定
    		// 假设传递的是Integer,这里这是的Object就会报错
    		list.set(0, obj); //error
    		list.set(0, list.get(0)); // error
    	}
    
    • 基本类型不能作为类型参数
    Map<int, char> map1 = new HashMap<>(); //error
    Map<Integer, Character> map2 = new HashMap<>(); //ok
    
    • 不能创建类型参数的示例
    public class Box<E> {
        public void add(Class<E> class) throws Exception {
            E e1 = new E(); // error
            E e2 = class.newInstance(); // ok
        }
    }
    
    • 不能用类型参数定义静态变量
    public class Box<E> {
        private class E value; // error
    }
    
    Box<Integer> box1 = new Box<>();
    Box<String> box2 = new Box<>();
    // 请问静态变量value是什么类型?答:没法确定
    
    • 泛型类型的类型参数不能用在静态方法上
    public class Box<E> {
        public static void show(E value) {} // error
    }
    
    • 类型参数不能跟 instanceof 一起使用
    ArraryList<Integer> list = new ArraryList<>();
    if(list instanceof ArraryList<Integer>) { // error
        
    }
    
    • 不能创建带有类型参数的数组
    Box<Integer>[] boxes1 = new Box<Integer>[];// error
    Box<Integer>[] boxes2 = new Box[4]; //or
    
    • 下面的方法不属于重载
    // error
    void test(Box<Integer> box) {
        
    }
    
    void test(Box<String> box) {
        
    }
    
    void test(Box<? extends Number> box) {
        
    }
    
    void test(Box<String> box) {
        
    }
    
    • 不能定义泛型的异常类
    // error
    public class MyException<T> extends Exception {
        
    }
    
    • catch 的异常类型不能用类型参数
    public static <T extend Exception> void test(Box<T> box) {
        try{
            
        } catch(T e) {
            
        }
    }
    
    • 下面的代码是正确的
    class Parser<T extends Exception> {
        //ok
        public void parse(File file) throws T {
            
        }
    }
    

    23、函数式接口01_Supplier

    • java.util.function 包中提供了很多常用的函数式接口
      • Supplier(美 [səˈplaɪər])
      • Consumer(美 [kənˈsuːmər])
      • Predicate(美 [ˈpredɪkeɪt])
      • Function(美 [ˈfʌŋkʃn])
      • ......

    Supplier

    @FunctionalInterface
    public interface Supplier<T> {
    
        /**
         * Gets a result.
         *
         * @return a result
         */
        T get();
    }
    
    • 有时使用 Supplier 传参,可以避免代码的浪费执行(有必要的时候再执行)
    	public static void main(String[] args) {
    		String s1 = "A";
    		String s2 = "B";
    		String s3 = "C";
    		getFirstNotEmptyString(s1, new Supplier<String>() {
    			@Override
    			public String get() {
    				//这种情况就没有打印输出日志
    				System.out.println("调用了supplier");
    				return s1 + s2 + s3;
    			}
    		});
    	}
    	static String getFirstNotEmptyString(String s1, Supplier<String> s2) {
    		if (s1 != null && s1.length() != 0) {
    			return s1;
    		}
    		if (s2 == null) {
    			return null;
    		}
    		String str = s2.get();
    		return (str != null && str.length() > 0) ? str : null;
    	}
    	
    	类似于|| 的短路功能 
    

    24、函数式接口02_Consumer

    定义:

    @FunctionalInterface
    public interface Consumer<T> {
    
        /**
         * Performs this operation on the given argument.
         *
         * @param t the input argument
         */
        void accept(T t);
    
        /**
         * Returns a composed {@code Consumer} that performs, in sequence, this
         * operation followed by the {@code after} operation. If performing either
         * operation throws an exception, it is relayed to the caller of the
         * composed operation.  If performing this operation throws an exception,
         * the {@code after} operation will not be performed.
         *
         * @param after the operation to perform after this operation
         * @return a composed {@code Consumer} that performs in sequence this
         * operation followed by the {@code after} operation
         * @throws NullPointerException if {@code after} is null
         */
        default Consumer<T> andThen(Consumer<? super T> after) {
            Objects.requireNonNull(after);
            return (T t) -> { accept(t); after.accept(t); };
        }
    }
    

    使用示例:

    	public static void main(String[] args) {
    		int[] nums = {11,2,33,44};
    		forEach(nums, (n) -> {
    			String result = ((n & 1) == 0) ? "偶数" : "奇数";
    			System.out.println(n + "是" + result);
    		});
    	}
    	static void forEach(int[] nums, Consumer<Integer> consumer ) {
    		if (nums == null || consumer == null) {
    			return;
    		}
    		for (int i : nums) {
    			consumer.accept(i);
    		}
    	} 
    	
    	回调就是将参数传出去
    

    andThen 使用示例:

    public static void main(String[] args) {
    		int[] nums = {11,2,33,44};
    		forEach(nums, (n) -> {
    			String result = ((n & 1) == 0) ? "偶数" : "奇数";
    			System.out.println(n + "是" + result);
    		},(n) -> {
    			String result = ((n %3 ) == 0) ? "能" : "不能";
    			System.out.println(n +  result + "能被3整除");
    		});
    	}
    	static void forEach(int[] nums, Consumer<Integer> consumer , Consumer<Integer> consumer2) {
    		if (nums == null || consumer == null) {
    			return;
    		}
    		for (int i : nums) {
    			consumer.andThen(consumer2).accept(i);
    		}
    	} 
    

    输出:

    11是奇数
    11不能能被3整除
    2是偶数
    2不能能被3整除
    33是奇数
    33能能被3整除
    44是偶数
    44不能能被3整除
    

    25、函数式接口03_Predicate

    定义:

    public interface Predicate<T> {
    
        /**
         * Evaluates this predicate on the given argument.
         *
         * @param t the input argument
         * @return {@code true} if the input argument matches the predicate,
         * otherwise {@code false}
         */
        boolean test(T t);
    
        /**
         * Returns a composed predicate that represents a short-circuiting logical
         * AND of this predicate and another.  When evaluating the composed
         * predicate, if this predicate is {@code false}, then the {@code other}
         * predicate is not evaluated.
         *
         * <p>Any exceptions thrown during evaluation of either predicate are relayed
         * to the caller; if evaluation of this predicate throws an exception, the
         * {@code other} predicate will not be evaluated.
         *
         * @param other a predicate that will be logically-ANDed with this
         *              predicate
         * @return a composed predicate that represents the short-circuiting logical
         * AND of this predicate and the {@code other} predicate
         * @throws NullPointerException if other is null
         */
        default Predicate<T> and(Predicate<? super T> other) {
            Objects.requireNonNull(other);
            return (t) -> test(t) && other.test(t);
        }
    
        /**
         * Returns a predicate that represents the logical negation of this
         * predicate.
         *
         * @return a predicate that represents the logical negation of this
         * predicate
         */
        default Predicate<T> negate() {
            return (t) -> !test(t);
        }
    
        /**
         * Returns a composed predicate that represents a short-circuiting logical
         * OR of this predicate and another.  When evaluating the composed
         * predicate, if this predicate is {@code true}, then the {@code other}
         * predicate is not evaluated.
         *
         * <p>Any exceptions thrown during evaluation of either predicate are relayed
         * to the caller; if evaluation of this predicate throws an exception, the
         * {@code other} predicate will not be evaluated.
         *
         * @param other a predicate that will be logically-ORed with this
         *              predicate
         * @return a composed predicate that represents the short-circuiting logical
         * OR of this predicate and the {@code other} predicate
         * @throws NullPointerException if other is null
         */
        default Predicate<T> or(Predicate<? super T> other) {
            Objects.requireNonNull(other);
            return (t) -> test(t) || other.test(t);
        }
    
        /**
         * Returns a predicate that tests if two arguments are equal according
         * to {@link Objects#equals(Object, Object)}.
         *
         * @param <T> the type of arguments to the predicate
         * @param targetRef the object reference with which to compare for equality,
         *               which may be {@code null}
         * @return a predicate that tests if two arguments are equal according
         * to {@link Objects#equals(Object, Object)}
         */
        static <T> Predicate<T> isEqual(Object targetRef) {
            return (null == targetRef)
                    ? Objects::isNull
                    : object -> targetRef.equals(object);
        }
    }
    

    使用示例:

    	public static void main(String[] args) {
    		int[] nums = {11,22,33,44};
    		String result = join(nums, (n)->{
    			if ((n&1) == 0) {
    				return true;
    			} else {
    				return false;
    			}
    		});
    		System.out.println(result); //22_44
    	}
    	
    	static String join(int[] nums, Predicate<Integer> p) {
    		if (nums == null || p == null) {
    			return null;
    		}
    		StringBuilder sb = new StringBuilder();
    		for (int i : nums) {
    			if (p.test(i)) {
    				sb.append(i).append("_");
    			};
    		}
    		sb.deleteCharAt(sb.length()-1);
    		return sb.toString();
    	}
    	删选元素,符合规则的拼接到一起
    

    26、函数式接口04_Function

    定义:

    
        /**
         * Applies this function to the given argument.
         *
         * @param t the function argument
         * @return the function result
         */
        R apply(T t);
    
        /**
         * Returns a composed function that first applies the {@code before}
         * function to its input, and then applies this function to the result.
         * If evaluation of either function throws an exception, it is relayed to
         * the caller of the composed function.
         *
         * @param <V> the type of input to the {@code before} function, and to the
         *           composed function
         * @param before the function to apply before this function is applied
         * @return a composed function that first applies the {@code before}
         * function and then applies this function
         * @throws NullPointerException if before is null
         *
         * @see #andThen(Function)
         */
        default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
            Objects.requireNonNull(before);
            return (V v) -> apply(before.apply(v));
        }
    
        /**
         * Returns a composed function that first applies this function to
         * its input, and then applies the {@code after} function to the result.
         * If evaluation of either function throws an exception, it is relayed to
         * the caller of the composed function.
         *
         * @param <V> the type of output of the {@code after} function, and of the
         *           composed function
         * @param after the function to apply after this function is applied
         * @return a composed function that first applies this function and then
         * applies the {@code after} function
         * @throws NullPointerException if after is null
         *
         * @see #compose(Function)
         */
        default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
            Objects.requireNonNull(after);
            return (T t) -> after.apply(apply(t));
        }
    
        /**
         * Returns a function that always returns its input argument.
         *
         * @param <T> the type of the input and output objects to the function
         * @return a function that always returns its input argument
         */
        static <T> Function<T, T> identity() {
            return t -> t;
        }
    }
    

    使用示例:

    	public static void main(String[] args) {
    		String[] strs = {"12", "400", "12"};
    		int result = sum2(strs, (str)-> {
    			return Integer.valueOf(str);
    		});
    		System.err.println(result); //424
    	}
    	static int sum2(String[] strs, Function<String, Integer> f) {
    		if (strs == null || f == null) {
    			return 0;
    		}
    		int result = 0;
    		for(String str: strs) {
    			result += f.apply(str);
    		}
    		return result;
    	}
    

    27、LinkedList

    • LinkedList 是一个双向链表
      • 实现了 List 接口
      • API 跟 ArrayList 类似

    28、Linked_ArrayList对比

    • ArrayList :开辟、销毁内存空间的次数相对较少,但可能造成内存空间浪费(可以通过缩容解决)
    • LinkedList :开辟、销毁内存空间的次数相对较多,但不会造成内存空间的浪费
    • 如果频繁在尾部进行添加、 删除操作, ArrayList、 LinkedList 均可选择
    • 如果频繁在头部进行添加、 删除操作,建议选择使用 LinkedList
    • 如果有频繁的(在任意位置) 添加、 删除操作,建议选择使用 LinkedList
    • 如果有频繁的查询操作(随机访问操作),建议选择使用 ArrayList

    29、Stack_Queue

    • Stack,译为“栈”,只能在一端进行操作
      • 往栈中添加元素的操作,一般叫做 push, 入栈
      • 从栈中移除元素的操作,一般叫做 pop,出栈(只能移除栈顶元素,也叫做:弹出栈顶元素)
      • 后进先出的原则, Last In First Out, LIFO
    • 注意:这里说的“栈”与内存中的“栈空间”是两个不同的概念

    Stack 常用方法

    E push(E item)
    E pop()
    E peek()
    int size()
    boolean empty()
    int search(Object o)
    

    Queue

    • Queue,译为“队列” ,只能在头尾两端进行操作
      • 队尾(rear):只能从队尾添加元素,一般叫做 入队
      • 队头(front):只能从队头移除元素,一般叫做 出队
      • 先进先出的原则, First In First Out, FIFO
    boolean add(E e) //入队
    boolean offer(E e) // 入队
    E remove(); //出队
    E poll() //出队
    E element() //返回队头
    boolean isEmpty();
    int size();
    

    30、HashSet_TreeSet

    • LinkedHashSet 在 HashSet 的基础上,记录了元素的添加顺序
    • TreeSet 要求元素必须具备可比较性,默认按照从小到大的顺序遍历元素

    31、HashMap_TreeMap

    • HashMap 存储的是键值对(key-value), Map 译为“映射”,有些编程语言中叫做“字典”

    • LinkedHashMap 在 HashMap 的基础上,记录了元素的添加顺序

    • TreeMap 要求 key 必须具备可比较性,默认按照从小到大的顺序遍历 key

    • List 的特点

      • 可以存储重复的元素
      • 可以通过索引访问元素
    • Set 的特点

      • 不可以存储重复的元素
      • 不可以通过索引访问元素
    • Map 的特点

      • 不可以存储重复的 key,可以存储重复的 value
      • 不可以通过索引访问 key-value
    • Set 的底层是基于 Map 实现的

      • HashSet 底层用了 HashMap
      • LinkedHashSet 底层用了 LinkedHashMap
      • TreeSet 底层用了TreeMap

    32、Collections

    • java.util.Collections 是一个常用的集合工具类,提供了很多实用的静态方法