1、集合框架概述
(1)集合框架作用
在实际开发中,我们经常会对一组相同类型的数据进行统一管理操作。到目前为止,我们可以使用数组结构、链表结构、二叉树结构来实现。
数组的最大问题在于数组中的元素个数是固定的,要实现动态数组,必竟还是比较麻烦, 自己实现链表或二叉树结构来管理对象更是不方便。
在JDK1.2版本后,JAVA完整的提供了类集合的概念,封装了一组强大的、非常方便的集合 框架API,让我们在开发中大大的提高了效率。 集合中分为三大接口:
Collection、Map、Iterator
(2)Collection接口
Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。
一些 collection 允许有重复的元素,而另一些则不允许。
一些 collection 是有序的,而另一些则是无序的。
JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些collection。 接口的定义:
public interface Collection<E>
extends Iterable<E>
2、集合框架List接口
(1)List接口
public interface List extends Collection<E>
有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
(2)ArrayList
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
List 接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有 元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。
- 使用add来添加元素,可以指定位置
- 使用size来获取长度大小
- 使用get来获取相应的数值
- 使用remove来删除某个元素
- 使用contains来查看是否包含某个元素
- 使用set来用指定元素替换列表中指定位置的元素
- 使用toArray将集合转换成数组
(3)Vector
public class Vector<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
Vector 类可以实现可增长的对象数组。 与数组一样, 它包含可以使用整数索引进行访问的组件。 但是, Vector 的大小可以根据需要增大或缩小, 以适应创建 Vector 后进行添加或移除项的操作
与ArrayList最大的区别是线程是安全的,适合多线程访问时使用,但在单线程效率较低
(4)LinkedList
public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, Serializable
List 接口的链接列表实现。 实现所有可选的列表操作, 并且允许所有元素(包括 null)。除了实现 List 接口外, LinkedList 类还为在列表的开头及结尾 get、 remove 和 insert 元素提供了统一的命名方法。
ListDemo
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
/**
* Collection接口:用于存储单个对象的集合
* List接口:
* 1、有序的,可以重复
* 2、允许多个 null 元素
* 3、具体的实现有常用的:ArrayList,Vector,LinkedList
* 在实际开发中,我们如何选择list的具体实现?
* 1、安全性问题 Vector
* 2、是否频繁插入,删除操作 LinkedList
* 3、是否是存储后遍历 ArrayList
*
* Set接口:
* @description
*/
public class ListDemo {
/**
* LinkedList
* 1、实现原理,采用双向链表结构实现
* 2、适合插入,删除操作,性能高
*
*/
private static void linkedList(){
LinkedList<String> list = new LinkedList<>();
list.add("王老师");
list.add("李老师");
list.add("张老师");
list.add("毕老师");
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
}
/**
* Vector
* 1、实现原理,采用动态对象数组实现,默认构造方法创建了一个大小为10的对象数组
* 2、扩充的算法:当增量为0时,扩充为原来大小的2倍,当增量大于0时,扩充为原来大小+增量
* 3、不适合删除或插入操作
* 4、为了防止数组动态扩充次数过多,建议创建Vector时,给定初始容量
* 5、线程安全,适合在多线程访问时使用,在单线程下使用效率较低
* 面试题 :Vector与ArrayList的区别?
*/
private static void vector(){
Vector<String> v = new Vector<>();
v.add("王老师");
v.add("李老师");
v.add("张老师");
v.add("毕老师");
for(int i=0;i<v.size();i++){
System.out.println(v.get(i));
}
}
/**
* ArrayList(1.8)
* 1、实现原理,采用动态对象数组实现,默认构造方法创建了一个空数组
* 2、第一次添加元素,扩展容量为10,之后的扩充算法:原来数组大小+原来数组的一半
* 3、不适合进行删除或插入操作
* 4、为了防止数组动态扩充次数过多,建议创建ArrayList时,给定初始容量
* 5、多线程中使用不安全,适合在单线程访问时使用,效率较高
* JDK1.2开始
*/
private static void arrayList(){
//使用集合来存储多个不同类型的元素(对象),那么在处理时会比较麻烦,实际开发中,不建议
//这样使用,我们应该在一个集合中存储相同的类型对象
List<String> list = new ArrayList<>();
list.add("王老师");
list.add("李老师");
list.add(1,"张老师");
list.add("毕老师");
// list.add(10);
//遍历集合
int size = list.size();
for(int i=0;i<size;i++){
System.out.println(list.get(i));
}
System.out.println(list.contains("王老师"));
list.remove("毕老师");
System.out.println(list.size());
list.set(0,"赵老师");
int index = list.indexOf("李老师");
System.out.println(index);
String[] strings = list.toArray(new String[list.size()]);
for(String str:strings){
System.out.println(str);
}
System.out.println("--------------");
String[] array = list.toArray(new String[]{});
for(String s: array){
System.out.println(s);
}
System.out.println("---------------");
for(String str:list){
System.out.println(str);
}
}
public static void main(String[] args) {
// arrayList();
vector();
// linkedList();
}
}
3、 集合框架Set接口
(1)Set接口
public interface Set<E> extends Collection<E>
一个不包含重复元素的 collection。 更确切地讲, set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2, 并且最多包含一个 null 元素。 正如其名称所暗示的, 此接口模仿了数学上的 set 抽象。
(2)HashSet
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable
类实现 Set 接口, 由哈希表(实际上是一个 HashMap 实例) 支持。 它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。 此类允许使用 null 元素
hashCode深入分析:
hashcode() 方法, 在object类中定义如下:
public native int hashCode();
hashCode是本地方法, 它的实现是根据本地机器相关, 当然我们可以在自己写的类中覆盖hashcode()方法, 比如String、 Integer、 Double… 等等这些类都是覆盖了hashcode()方法的。
在java的集合中, 判断两个对象是否相等的规则是:可通过重写hashCode以及equals
- 判断两个对象的hashCode是否相等如果不相等, 认为两个对象也不相等, 结束如果相等, 转入2
- 判断两个对象用equals运算是否相等如果不相等, 认为两个对象也不相等如果相等, 认为两个对象相等
(equals()是判断两个对象是否相等的关键)
没有get方法
(3)TreeSet
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, Serializable
基于 TreeMap 的 NavigableSet 实现。 使用元素的自然顺序对元素进行排序, 或者根据创建 set 时提供的 Comparator 进行排序, 具体取决于使用的构造方法。
(4)LinkedHashSet
public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, Serializable
具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。 此实现与 HashSet 的不同之外在于, 后者维护着一个运行于所有条目的双重链接列表。 此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序) 进行迭代。 注意, 插入顺序不受在 set 中重新插入的 元素的影响。 (如果在 s.contains(e) 返回 true 后立即调用 s.add(e), 则元素 e 会被重新插入到 set s 中。 )
SetDemo
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
/**
* Set接口
* 1、无序的(不保证顺序)
* 2、不允许重复元素
* HashSet、TreeSet、LinkedHashSet
*
* 如果要排序,选择treeSet
* 如果不要排序,也不用保正顺序选择HashSet
* 不要排序,要保正顺序,选择LinkedHashSet
* @description
*/
public class SetDemo {
/**
* 哈希表和链接列表实现,
* 维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。
*/
private static void linkedHashSet(){
LinkedHashSet<Cat> set = new LinkedHashSet<>();
Cat c1 = new Cat("miaomiao",5,1);
Cat c2 = new Cat("huahua",2,2);
Cat c3 = new Cat("tom",5,3);
Cat c4 = new Cat("miaomiao",3,1);
set.add(c1);
set.add(c2);
set.add(c3);
set.add(c4);
for(Cat c: set){
System.out.println(c);
}
}
/**
* 有序的,基于TreeMap(二叉树数据结构),对象需要比较大小,通过对象比较器来实现,
* 对象比较器还可以用来去除重复元素,如果自定义的数据类,没有实现比较器接口,将无法添加到TreeSet集合中。
*/
private static void treeSet(){
TreeSet<Cat> tree = new TreeSet<>(new CatComparator());
Cat c1 = new Cat("miaomiao",5,1);
Cat c2 = new Cat("huahua",2,2);
Cat c3 = new Cat("tom",5,3);
Cat c4 = new Cat("miaomiao",3,1);
tree.add(c1);
tree.add(c2);
tree.add(c3);
tree.add(c4);
System.out.println(tree.size());
for(Cat c: tree){
System.out.println(c);
}
}
/**
* HashSet
* 1、实现原理,基于哈希表(HashMap)实现
* 2、不允许重复,可以有一个NULL元素
* 3、不保证顺序恒久不变
* 4、添加元素时把元素作为HashMap的key存储,HashMap的value使用一个固定的object对象
* 5、排除重复元素是通过equals来检查对象是否相同
* 6、判断两个对象是否相同,先判断两个对象的hashCode是否相同(如果两个对象的hashCode相同,不一定是同一个对象,如果不同,那一定不是
* 同一个对象),如果不同,则两个对象不是同一个对象,如果相同,还要进行equals判断,equals相同则是同一个对象,不同则不是同一个对比象。
* 7、自定义对象要认为属性值都相同时为同一个对象,有这种需求时,那么我们要重写对象所在类的hashCode和equals方法。
*
* 小结
* (1)哈希表的存储结构:数组+链表,数组里的每个元素以链表的形式存储
* (2)如何把对象存储到哈希表中,先计算对象的hashCode值,再对数组的长度求余数,来决定对象要存储在数组中的哪个位置
* (3)解决hashSet中的重复值使用的方式是,参考第6点
*/
private static void hashSet(){
Set<String> set = new HashSet<>();
set.add("飞飞");
set.add("备备");
set.add("亮亮");
set.add("关关");
set.add("曹操");
set.add("亮亮");
System.out.println(set.size());
String[] names = set.toArray(new String[]{});
for(String s: names){
System.out.println(s);
}
Cat c1 = new Cat("miaomiao",5,1);
Cat c2 = new Cat("huahua",2,2);
Cat c3 = new Cat("tom",5,3);
Cat c4 = new Cat("miaomiao",5,1); //c4与c1使用equals不同
Set<Cat> cats = new HashSet<>();
cats.add(c1);
cats.add(c2);
cats.add(c3);
cats.add(c4);
//cats.add(c1);
System.out.println(cats.size());
for(Cat c: cats){
System.out.println(c);
}
System.out.println("c1="+c1.hashCode());
System.out.println("c2="+c2.hashCode());
System.out.println("c3="+c3.hashCode());
System.out.println("c4="+c4.hashCode());
}
public static void main(String[] args) {
// hashSet();
// treeSet();
linkedHashSet();
}
}
Cat
public class Cat {
private String name;
private int age;
private int id;
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;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Cat [name=" + name + ", age=" + age + ", id=" + id + "]";
}
public Cat(String name, int age, int id) {
super();
this.name = name;
this.age = age;
this.id = id;
}
public Cat() {
super();
// TODO Auto-generated constructor stub
}
@Override
public int hashCode() {
final int prime = 31; //系数 31*1+5 * 31+1 11111
int result = 1;
result = prime * result + age;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Cat other = (Cat) obj;
if (age != other.age)
return false;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
CatComparator
package com.vince;
import java.util.Comparator;
public class CatComparator implements Comparator<Cat> {
@Override
public int compare(Cat o1, Cat o2) {
return o1.getAge()-o2.getAge();
}
}
4、 集合框架Iterator接口
(1)集合输出
前面我们已经学习了集合的基本操作, 很多情况下, 我们需要把集合的内容进行输出, 也就是遍历集合。
遍历集合的方式有以下几种:
- Iterator
- ListIterator
- Enumeration
- foreach
其中Iterator的使用率最高, 在JDK1.5后新增的foreach也被大量使用。
(2)Iterator接口
public interface Iterator<E>
对 collection 进行迭代的迭代器。 迭代器取代了 Java Collections Framework 中的 Enumeration。
(3)ListIterator
public interface ListIterator<E>
extends Iterator<E>
系列表迭代器, 允许程序员按任一方向遍历列表、 迭代期间修改列表, 并获得迭代器在列表中的当前位置
(4)Enumeration
public interface Enumeration<E>
实现 Enumeration 接口的对象, 它生成一系列元素, 一次生成一个。 连续调用nextElement 方法将返回一系列的连续元素。
注: 此接口的功能与 Iterator 接口的功能是重复的。 此外, Iterator 接口添加了一个可选的移除操作, 并使用较短的方法名。 新的实现应该优先考虑使用 Iterator 接口而不是Enumeration 接口。
(5)forEach
在前面的知识讲解中, 我们使用forEach来输出数组的内容, 那么也可以输出集合中的内容。 在使用forEach输出的时候一定要注意的是, 创建集合时要指定操作泛型的类型。
List<Integer> numbers = new ArrayList<>();
JDK1.8新特性:
//no.1
numbers.forEach((Integer integer) -> {System.out.println(integer);});
//no.2
numbers.forEach(integer -> {System.out.println(integer);});
//no.3
numbers.forEach(integer -> System.out.println(integer));
//no.4
numbers.forEach(System.out::println);
//no.5
numbers.forEach(new MyConsumer());
IteratorDemo
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* 集合的输出(迭代)
* @description
*/
public class IteratorDemo {
//断言接口
private static void predicateTest(){
List<String> list = Arrays.asList("Larry", "Moe", "Curly","Tom","QF_vince");
List<String> result = filter(list,(s)->s.contains("o"));
result.forEach(System.out::println);
}
private static List<String> filter(List<String> list,Predicate<String> p){
List<String> results = new ArrayList<>();
for (String s : list) {
if(p.test(s)){ //测试是否符合要求
results.add(s);
}
}
return results;
}
//Supplier 代表结果供应商
private static void supplierTest(){
List<Integer> list = getNums(10,()->(int)(Math.random() * 100));
list.forEach(System.out::println);
}
private static List<Integer> getNums(int num,Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for(int i=0;i<num;i++){
list.add(sup.get());
}
return list;
}
//Function表示接受一个参数并产生结果的函数
private static void functionTest(){
String s = strToUpp("qf_vince",(str)->str.toUpperCase());
System.out.println(s);
}
public static String strToUpp(String str,Function<String,String> f){
return f.apply(str);
}
/**
* JDK1.8新的迭代方法
*/
private static void foreach(){
List<String> list = new ArrayList<>();
list.add("tom");
list.add("jack");
list.add("job");
list.add("lily");
//Consumer
list.forEach(s->System.out.println(s));
//list.forEach(System.out::println);
}
private static void enumeration(){
Vector<String> vs = new Vector<>();
vs.add("tom");
vs.add("jack");
vs.add("bob");
vs.add("lily");
Enumeration<String> es = vs.elements();
while(es.hasMoreElements()){
System.out.println(es.nextElement());
}
}
//foreach(1.5后)
private static void foreach(Collection<Cat> c){
for(Cat cat: c){
System.out.println(cat);
}
}
//iterator(1.5之前统一的迭代集合方式)
private static void iterator(Collection<Cat> c){
Iterator<Cat> iter = c.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
}
public static void main(String[] args) {
List<Cat> list = new ArrayList<>();
Cat c1 = new Cat("miaomiao",5,1);
Cat c2 = new Cat("huahua",2,2);
Cat c3 = new Cat("tom",5,3);
Cat c4 = new Cat("miaomiao",3,1);
list.add(c1);
list.add(c2);
list.add(c3);
list.add(c4);
// iterator(list);
// foreach(list);
// enumeration();
// foreach();
// functionTest();
// supplierTest();
// predicateTest();
String[] strs={"ni","hao","aho","oerh"};
List<String> li=Arrays.asList(strs); //使用Arrays.asList()制作的集合,其长度一定不能增加,故要将其转换
// List<String> li=Arrays.asList("ni","hao","aho","oerh");
ArrayList<String> li1=new ArrayList<>(li);
li1.add("qwe");
li1.forEach(System.out::println);
List<String> li2=new ArrayList<>();
for(String str:li1){
if(str.contains("o")){
li2.add(str);
}
}
li2.forEach(System.out::println);
}
}
5、 JDK1.8新特性
Consumer接口 消费者接口
Function
Supplier接口 代表结果供应商。
Predicate接口 断言接口
(1)Stream概念
Stream是元素的集合, 这点让Stream看起来有些类似Iterator;
可以支持顺序和并行的对原Stream进行汇聚的操作;
我们可以把Stream当成一个高级版本的Iterator。 原始版本的Iterator, 用户只能一个一个的遍历元素并对其执行某些操作; 高级版本的Stream, 用户只要给出需要对其包含的元素执行什么操作, 比如“ 过滤掉长度大于10的字符串” 、 “ 获取每个字符串的首字母”等, 具体这些操作如何应用到每个元素上, 就给Stream就好了!
(2)Stream常见操作
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Stream接口:不是存储数据结构,数据源可以是一个集合,为了函数式编程创造 ,
* 惰式执行,数据只能被消费一次
*
* 两种类型的操作方法:
* 1、中间操作(生成一个Stream)
* 2、结束操作(执行计算操作)
* @description
*/
public class StreamDemo {
public static void main(String[] args) {
Stream<String> stream = Stream.of("good","good","study","day","day","up");
//foreach方法
//stream.forEach((str)->System.out.println(str));
//stream.forEach(System.out::println);
//filter 过滤
//stream.filter((s)->s.length()>3).forEach(System.out::println);
//distinct 去重
//stream.distinct().forEach(s->System.out.println(s));
//map 映射
//stream.map(s->s.toUpperCase()).forEach(s->System.out.println(s));
//flatMap 展平
// Stream<List<Integer>> ss = Stream.of(Arrays.asList(1,2,3),Arrays.asList(4,5));
// ss.flatMap(list->list.stream()).forEach(System.out::println);
//reduce 归纳
// Optional<String> opt = stream.reduce((s1,s2)->s1.length()>=s2.length()?s1:s2);
// System.out.println(opt.get());
//collect 将stream转为List
// List<String> list = stream.collect(Collectors.toList());
// list.forEach(s->System.out.println(s));
//集合转为流,筛选后,再转为数组
//数组转为流,获取最小值
List<Integer> li=Arrays.asList(1,5,4,2,3);
Integer[] integers = li.stream().filter(s -> s > 2).toArray(Integer[]::new);
Optional<Integer> reduce = Arrays.stream(integers).reduce((s1, s2) -> (s1 > s2 ? s1 : s2));
System.out.println(reduce.get());
//排序后转为数组
Integer[] integers1 = li.stream().sorted().toArray(Integer[]::new);
//:: 方法引用
//引用静态方法 Integer::valueOf
//引用对象的方法 list::add
//引用构造方法 ArrayList::new
}
}
6、 集合框架Map接口
(1)Map接口
public interface Map<K,V>
将键映射到值的对象, 一个映射不能包含重复的键; 每个键最多只能映射到一个值。
(2)HashMap
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
基于哈希表的 Map 接口的实现。 此实现提供所有可选的映射操作, 并允许使用 null 值和 null 键。(除了非同步和允许使用 null 之外, HashMap 类与 Hashtable 大致相同。 ) 此类不保证映射的顺序, 特别是它不保证该顺序恒久不变
(3)Hashtable
public class Hashtable<K,V> extends Dictionary<K,V>
implements Map<K,V>, Cloneable, Serializable
此类实现一个哈希表, 该哈希表将键映射到相应的值。 任何非 null 对象都可以用作键或值。
为了成功地在哈希表中存储和获取对象, 用作键的对象必须实现 hashCode 方法和 equals 方法
(4)LinkedHashMap
public class LinkedHashMap<K,V>
extends HashMap<K,V> implements Map<K,V>
Map 接口的哈希表和链接列表实现, 具有可预知的迭代顺序。 此实现与 HashMap 的不同之处在于, 后者维护着一个运行于所有条目的双重链接列表。
(5)TreeMap
public class TreeMap<K,V> extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, Serializable
基于红黑树(Red-Black tree) 的 NavigableMap 实现。 该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序, 具体取决于使用的构造方法。
(6)1.8 Map接口的新方法
在JDK8中Map接口提供了一些新的便利的方法。 因为在本文中我所提到的所有Map方法都是以默认值方法的方式实现的, 所以现有的Map接口的实现可以直接拥有这些在默认值方法中定义的默认行为, 而不需要新增一行代码。
- getOrDefault(Object, V)
- putIfAbsent(K,V)
- remove(Object key, Object value)
- replace(K,V)
- replace(K,V,V)
- compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
- computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
- merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)
MapDemo
package com.vince;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
/**
* Map接口:
* 1、键值对存储一组对象
* 2、Key不能重复(唯一),Value可以重复
* 3、具体的实现类:HashMap TreeMap Hashtable LinkedHashMap
* 4、HashMap 与 Hashtable的区别?
* 5、如何选择使用哪个?
* 排序且选择二叉树存储:TreeMap
* 不要求排序且单线程:HashMap
* 多线程:Hashtable
* 保证顺序;LinkedHashMap
* 6、数据结构:数组、链表、二叉树(红黑树)、哈希表(数组+链表)、栈、队列
* @description
*/
public class MapDemo {
/**
* 基于二叉树的红黑树实现
*/
private static void treeMap(){
Map<String,String> map = new TreeMap<>();
// map.put("one", "Lily");
// map.put("two", "Tom");
// map.put("three", "Bin");
// map.forEach((key,value)->System.out.println(key+"->"+value));
//
Map<Dog,String> dogs = new TreeMap<>();
dogs.put(new Dog(1,"2ha",3), "dog1");
dogs.put(new Dog(1,"wangwang",2), "dog2");
dogs.put(new Dog(3,"hsq",4), "dog3");
dogs.forEach((key,value)->System.out.println(key+"->"+value));
}
/**
* LinkedHashMap是HashMap的子类,由于HashMap不能保正顺序恒久不变,此类使用一个双重链表来维护
* 元素添加的顺序。
*/
private static void linkedHashMap(){
Map<String,String> table = new LinkedHashMap<>();
table.put("one", "Lily");
table.put("two", "Tom");
table.put("three", "Bin");
table.forEach((key,value)->System.out.println(key+"->"+value));
}
/**
* JDK1.0开始
* 基于哈希表实现(数组+链表)
* 默认数组大小为11,加载因子0.75
* 扩充方式:原数组大小<<1 (*2) +1
* 线程安全的,用在多线程访问时
*/
private static void hashtable(){
Map<String,String> table = new Hashtable<>();
table.put("one", "Lily");
table.put("two", "Tom");
table.put("three", "Bin");
table.forEach((key,value)->System.out.println(key+"->"+value));
}
/**
* HashMap的现实原理:
* 1、基于哈希表(数组+链表+二叉树(红黑树))1.8JDK
* 2、默认加载因子为0.75,默认数组大小是16,加载因子含义:如果空间的75%被存满,则该数组空间已经被存满
* 3、把对象存储到哈希表中,如何存储?
* 把key对象通过hash()方法计算hash值,然后用这个hash值对数组长度取余数(默认16),来决定该对KEY对象
* 在数组中存储的位置 ,当这个位置 有多个对象时,以链表结构存储,JDK1.8后,当链表长度大于8时,链表将转换为
* 红黑树结构存储。
* 这样的目的,是为了取值更快,存储的数据量越大,性能的表现越明显
* 4、扩充原理:当数组的容量超过了75%,那么表示该数组需要扩充,如何扩充?
* 扩充的算法是:当前数组容量<<1 (相当于是乘2),扩大1倍, 扩充次数过多,会影响性能,每次扩充表示哈希表重新
* 散列(重新计算每个对象的存储位置),我们在开发中尽量要减少扩充次数带来的性能问题。
* 5、线程不安全,适合在单线程中使用
*/
private static void hashMap(){
Map<Integer,String> map = new HashMap<>();
map.put(1, "Tom");
map.put(2, "Jack");
map.put(3, "Vince");
map.put(4, "Bin");
map.put(5, "Lily");
System.out.println("size="+map.size());
//从MAP中取值
System.out.println(map.get(1));//通过key取value
//map的遍历
//1 遍历Entry
Set<Entry<Integer,String>> entrySet = map.entrySet();
for(Entry e: entrySet){
System.out.println(e.getKey()+"->"+e.getValue());
}
System.out.println("--------");
//2 遍历键
Set<Integer> keys = map.keySet();
for(Integer i: keys){
String value = map.get(i);
System.out.println(i+"->"+value);
}
System.out.println("--------");
//3 遍历值
Collection<String> values = map.values();
for(String value: values){
System.out.println(value);
}
System.out.println("--------");
//4 foreach
Map<Integer,String> map1=new HashMap<>();
map.forEach((key,value)->{
if(key>3){
map1.put(key+1,value);
}
});
map1.forEach((key,value)->System.out.println(key+"->"+value));
System.out.println(map.containsKey(7));
//hash
Integer key = 1434;
System.out.println( 1434 % 16 );
}
public static void main(String[] args) {
hashMap();
// hashtable();
// treeMap();
}
}
Dog
package com.vince;
public class Dog implements Comparable<Dog>{
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
public Dog(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public Dog() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Dog [id=" + id + ", name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Dog o) {
return this.id-o.id;
}
}
MapNewMethodDemo
import java.util.HashMap;
import java.util.Map;
/**
* Map接口1.8新增方法介绍
* @description
*/
public class MapNewMethodDemo {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
map.put(1, "jack");
map.put(2, "tom");
map.put(3, "lily");
String value1 = map.getOrDefault(4, "null");
System.out.println(value1);
// String s = map.get(5);
// if(s==null){
// System.out.println();
// }else{
//
// }
String val = map.put(3,"vince");
System.out.println(val); //返回以前的值
map.forEach((key,value)-> System.out.println(key+"->"+value));
//只会添加不存在相同key的值
String val1 = map.putIfAbsent(3, "vince");
System.out.println(val1);
map.forEach((k,v)->System.out.println(k+"->"+v));
//根据键和值都匹配时才删除
map.remove(1, "jack");
//替换map中的值
map.replace(3, "vince");
map.replace(3, "lily", "vince");
//计算操作数据
map.compute(1, (k,v1)->v1+"1");
map.computeIfAbsent(5,(val2)->val2+"test");
//合并
map.merge(8, "888", (oldVal,newVal)->oldVal.concat(newVal));
map.forEach((k,v)->System.out.println(k+"->"+v));
}
}
7、 Collections工具类
Collections类
Collections工具类提供了大量针对Collection/Map的操作, 总体可分为四类, 都为静态(static) 方法:
(1)排序操作(主要针对List接口相关)
- reverse(List list): 反转指定List集合中元素的顺序
- shuffle(List list): 对List中的元素进行随机排序(洗牌)
- sort(List list): 对List里的元素根据自然升序排序
- sort(List list, Comparator c): 自定义比较器进行排序
- swap(List list, int i, int j): 将指定List集合中i处元素和j出元素进行交换
- rotate(List list, int distance): 将所有元素向右移位指定长度, 如果distance等于size那么结果不变
(2)查找和替换(主要针对Collection接口相关)
- binarySearch(List list, Object key): 使用二分搜索法, 以获得指定对象在List中的索引, 前提是集合已经排序
- max(Collection coll): 返回最大元素
- max(Collection coll, Comparator comp): 根据自定义比较器, 返回最大元素
- min(Collection coll): 返回最小元素
- min(Collection coll, Comparator comp): 根据自定义比较器, 返回最小元素
- fill(List list, Object obj): 使用指定对象填充
- frequency(Collection Object o): 返回指定集合中指定对象出现的次数
- replaceAll(List list, Object old, Object new): 替换
(3)同步控制
Collections工具类中提供了多个synchronizedXxx方法, 该方法返回指定集合对象对应的同步对象, 从而解决多线程并发访问集合时线程的安全问题。 HashSet、 ArrayList、 HashMap都是线程不安全的, 如果需要考虑同步,则使用这些方法。 这些方法主要有: synchronizedSet、 synchronizedSortedSet、 synchronizedList、synchronizedMap、 synchronizedSortedMap。
特别需要指出的是, 在使用迭代方法遍历集合时需要手工同步返回的集合
(4)设置不可变集合
Collections有三类方法可返回一个不可变集合:
- emptyXxx(): 返回一个空的不可变的集合对象
- singletonXxx(): 返回一个只包含指定对象的, 不可变的集合对象。
- unmodifiableXxx(): 返回指定集合对象的不可变视图
(5)其它
- disjoint(Collection c1, Collection c2) - 如果两个指定 collection 中没有相同的元素, 则返回 true。
- addAll(Collection<? super T> c, T… a) - 一种方便的方式, 将所有指定元素添加到指定 collection 中。
- Comparator reverseOrder(Comparator cmp) - 返回一个比较器, 它强行反转指定比较器的顺序。 如果指定比较器为 null, 则此方法等同于 reverseOrder()(换句话说, 它返回一个比较器, 该比较器将强行反转实现Comparable 接口那些对象 collection 上的自然顺序)。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Collections工具类
* @description
*/
public class CollectionsDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("jack");
list.add("tom");
list.add("lily");
list.add("lily");
System.out.println(list); //[jack, tom, lily, lily]
//(1)排序操作
//反转数组
// Collections.reverse(list); //[lily, lily, tom, jack]
//随机排序
// Collections.shuffle(list); //[lily, lily, jack, tom]
//sort按自然的升序排序
// Collections.sort(list); //[jack, lily, lily, tom]
//再多传一个排序对象
// Collections.sort(list, c);
//交换两个值
// Collections.swap(list, 0, 2); //[lily, tom, jack, lily]
//旋转,将所有元素向右移动指定位置
// Collections.rotate(list, 1); //[lily, jack, tom, lily]
//(2)查找替换
//找某个值
// System.out.println(Collections.binarySearch(list, "tom")); //1
//返回最大值
// System.out.println(Collections.max(list)); //tom
//返回最小值
// System.out.println(Collections.min(list)); //jack
//填充
// Collections.fill(list, "bin"); //[bin, bin, bin, bin]
//返回集合中指定对象出现的次数
// System.out.println(Collections.frequency(list, "lily")); //2
//替换
// Collections.replaceAll(list, "lily", "bin"); //[jack, tom, bin, bin]
//(3)同步控制
// List<String> syncList = Collections.synchronizedList(new ArrayList<String>());
//(4)设置不可变集合
// List<String> sList = Collections.emptyList();
// sList.add("bin"); //会报错
//(5)反转后排序:倒序
// Collections.sort(list,Collections.reverseOrder()); //[tom, lily, lily, jack]
}
public static List<String> query(){
List<String> list = null;
//查不到,返回一个空集合
return Collections.emptyList();
}
}
8、Optional容器类(JDK1.8)
Optional容器类(JDK1.8)
这是一个可以为null的容器对象。 如果值存在则isPresent()方法会返回true, 调用get()方法会返回该对象
- of:为非null的值创建一个Optional。
- ofNullable:为指定的值创建一个Optional, 如果指定的值为null, 则返回一个空的Optional。
- isPresent:如果值存在返回true, 否则返回false。
- get:如果Optional有值则将其返回, 否则抛出NoSuchElementException。
- ifPresent:如果Optional实例有值则为其调用consumer, 否则不做处理
- orElse:如果有值则将其返回, 否则返回指定的其它值
- orElseGet:orElseGet与orElse方法类似, 区别在于得到的默认值。 orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值。
- orElseThrow:如果有值则将其返回, 否则抛出supplier接口创建的异常。
- map:如果有值, 则对其执行调用mapping函数得到返回值。 如果返回值不为null, 则创建包含mapping返回值的Optional作为map方法返回值, 否则返回空Optional。
- flatMap:如果有值, 为其执行mapping函数返回Optional类型返回值, 否则返回空Optional。 flatMap与map(Funtion) 方法类似, 区别在于flatMap中的mapper返回值必须是Optional。 调用结束时,flatMap不会对结果用Optional封装。
- filter:如果有值并且满足断言条件返回包含该值的Optional, 否则返回空Optional
package com.vince;
import java.util.Optional;
/**
* Optional JDK1.8容器类
* @description
*/
public class OptionalDemo {
public static void main(String[] args) {
//创建Optional对象的方式
Optional<String> optional = Optional.of("bin");
// Optional<String> optional2 = Optional.ofNullable("bin");
Optional<String> optional3 = Optional.empty();
System.out.println(optional.isPresent()); //true
System.out.println(optional.get()); //bin
optional.ifPresent((value)->System.out.println(value)); //如果有值则调用 //bin
System.out.println(optional.orElse("无值")); //如果有值则返回,否则返回其他值 //bin
System.out.println(optional.orElseGet(()->"default")); //设定一个默认值 //bin
// try {
// optional3.orElseThrow(Exception::new);
// } catch (Exception e) {
// e.printStackTrace();
// }
Optional<String> optional4 = optional.map((value)->value.toUpperCase()); //BIN
System.out.println(optional4.orElse("no found"));
optional4 = optional.flatMap((value)->Optional.of(value.toUpperCase()+"-flatMap")); //BIN-flatMap
System.out.println(optional4.orElse("no found"));
optional4 = optional.filter((value)->value.length()>3); //这个值的长度小于3
System.out.println(optional4.orElse("这个值的长度小于3"));
}
}
9、 Queue、Deque接口
队列(Queue) 是一种特殊的线性表, 是一种先进先出( FIFO) 的数据结构。 它只允许在表的前端( front) 进行删除操作, 而在表的后端( rear) 进行插入操作。 进行插入操作的端称为队尾, 进行删除操作的端称为队头。 队列中没有元素时, 称为空队列。
LinkedList是Queue接口的实现类
- boolean add(E e) : 将指定的元素插入此队列(如果立即可行且不会违反容量限制) , 在成功时返回 true, 如果当前没有可用的空间, 则抛出 IllegalStateException。
- E element() : 获取, 但是不移除此队列的头。
- boolean offer(E e) : 将指定的元素插入此队列(如果立即可行且不会违反容量限制),当使用有容量限制的队列时, 此方法通常要优于 dd(E), 后者可能无法插入元素, 而只是抛出一个异常。
- E peek() : 获取但不移除此队列的头; 如果此队列为空, 则返回 null。
- E poll() : 获取并移除此队列的头, 如果此队列为空, 则返回 null。
- E remove() : 获取并移除此队列的头。
Deque: 一个线性 collection, 支持在两端插入和移除元素。
此接口既支持有容量限制的双端队列, 也支持没有固定大小限制的双端队列。
接口定义在双端队列两端访问元素的方法。 提供插入、 移除和检查元素的方法
import java.util.Deque;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
/**
* Queue接口:队列,是一种先进先出的线性数据结构(排队)
* LinkedList类实现了queue接口
* 请求队列,消息队列,任务
*
* Deque接口:双端队列
* Stack:堆栈 :先进后出
* @description
*/
public class QueueDequeDemo {
private static void stack(){
//堆栈:先进后出
Stack<String> s = new Stack<>();
//压栈
s.push("Bin");
s.push("Tom");
s.push("Lily");
System.out.println(s.pop()); //Lily
System.out.println(s.peek()); //Tom
System.out.println(s.pop()); //Tom
System.out.println(s.pop()); //Bin
}
private static void deque(){
//双端队列
Deque<String> deque = new LinkedList<>();
deque.add("小花");
deque.add("小黑");
deque.add("小小");
deque.add("小白");
deque.add("小丽");
System.out.println(deque.getFirst()); //小花
System.out.println(deque.getLast()); //小丽
}
private static void queue(){
//队列:先进先出
Queue<String> queue = new LinkedList<>();
//往队列里添加元素
queue.add("小花");
queue.add("小黑");
queue.add("小小");
queue.add("小白");
queue.add("小丽");
//队列的长度大小
System.out.println(queue.size()); //5
//获取队列的头,但不移除,若为空返回null
System.out.println(queue.peek()); //小花
System.out.println(queue.size()); //5
//获取队列的头,并删除
System.out.println(queue.poll()); //小花
System.out.println(queue.size()); //4
System.out.println(queue);
queue.offer("小明");
System.out.println(queue);
}
public static void main(String[] args) {
// queue();
// deque();
stack();
}
}
10、对象一对多与多对多关系
OneToManyDemo
/**
* 对象的一对多关系
*
* @description
*/
public class OneToManyDemo {
public static void main(String[] args) {
Teacher t1 = new Teacher("张老师",18,"女");
Student s1 = new Student("小李",10);
Student s2 = new Student("小王",12);
Student s3 = new Student("小赵",11);
//关联关系
t1.getStudents().add(s1);
t1.getStudents().add(s2);
t1.getStudents().add(s3);
s1.setTeacher(t1);
s2.setTeacher(t1);
s3.setTeacher(t1);
print(t1);
}
private static void print(Teacher t1) {
System.out.println(t1.getName());
// for(Student s: t1.getStudents()){
// System.out.println(s);
// }
t1.getStudents().forEach(System.out::println);
}
}
Student
/**
*
* @description
*/
public class Student {
private int sid;
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
private String sname;
private int age;
private Teacher teacher;
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String sname, int age) {
super();
this.sname = sname;
this.age = age;
}
public Student() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Student [sname=" + sname + ", age=" + age + "]";
}
}
Teacher
import java.util.HashSet;
//一个老师对应多个学生
public class Teacher {
private String name;
private int age;
private String sex;
private HashSet<Student> students = new HashSet<>();
public HashSet<Student> getStudents() {
return students;
}
public void setStudents(HashSet<Student> students) {
this.students = students;
}
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;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Teacher [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
public Teacher() {
super();
// TODO Auto-generated constructor stub
}
public Teacher(String name, int age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
}
StudentAndCourse
public class StudentAndCourse {
private int id;
private int sid;
private int cid;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public int getCid() {
return cid;
}
public void setCid(int cid) {
this.cid = cid;
}
}
11、迭代器设计模式
提供一个方法按顺序遍历一个集合内的元素, 而又不需要暴露该对象的内部表示。
应用场景:
- 访问一个聚合的对象, 而不需要暴露对象的内部表示
- 支持对聚合对象的多种遍历
- 对遍历不同的对象, 提供统一的接口
迭代器模式的角色构成:
- 迭代器角色(Iterator) :定义遍历元素所需要的方法, 一般来说会有这么三个方法: 取得下一个元素的方法next(), 判断是否遍历结束的方法hasNext(), 移出当前对象的方法remove()
- 具体迭代器角色(Concrete Iterator) : 实现迭代器接口中定义的方法, 完成集合的迭代
- 容器角色(Aggregate): 一般是一个接口, 提供一个iterator()方法, 例如java中的Collection接口,List接口, Set接口等
- 具体容器角色(ConcreteAggregate) : 就是抽象容器的具体实现类, 比如List接口的有序列表实现ArrayList, List接口的链表实现LinkedList, Set接口的哈希列表的实现HashSet等
Iterator
package iterator;
/**
* 迭代器的接口
* @description
*/
public interface Iterator {
public boolean hasNext();
public Object next();
}
ConcreteIterator
package iterator;
/**
* 迭代器接口的具体实现类
* @description
*/
public class ConcreteIterator implements Iterator{
private MyList list = null;
private int index;//迭代器的指针
public ConcreteIterator(MyList list) {
this.list = list;
}
@Override
public boolean hasNext() {
if(index>=list.getSize())
return false;
else return true;
}
@Override
public Object next() {
Object obj = list.get(index);
index++;
return obj;
}
}
MyList
package iterator;
/**
* 容器的接口
* @description
*/
public interface MyList {
void add(Object e);
Object get(int index);
Iterator iterator();
int getSize();
}
ConcreteAggregate
package iterator;
/**
* 容器接口的具体实现类
* @description
*/
public class ConcreteAggregate implements MyList{
private Object[] elements;//对象数组
private int size;
private int index;
public ConcreteAggregate() {
elements = new Object[100];
}
@Override
public void add(Object e) {
elements[index++] = e;
size++;
}
@Override
public Object get(int index) {
return elements[index];
}
@Override
public Iterator iterator() {
return new ConcreteIterator(this);
}
@Override
public int getSize() {
return size;
}
}
Test
package iterator;
/**
* @description
*/
public class Test {
public static void main(String[] args) {
MyList list = new ConcreteAggregate();
list.add("刘备");
list.add("张飞");
list.add("关羽");
list.add("曹操");
list.add("诸葛亮");
Iterator iter = list.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
}
}
12、guava对集合的支持
版本下载: https://repo1.maven.org/maven2/com/google/guava/guava/
Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库, 例如: 集合 [collections] 、 缓存 [caching] 、 原生类型支持 [primitives support] 、 并发库 [concurrency libraries] 、 通用注解 [common annotations] 、 字符串处理 [string processing] 、 I/O 等等。 所有这些工具每天都在被Google的工程师应用在产品服务中。
Guava对JDK集合的扩展, 这是Guava最成熟和为人所知的部分。
- 不可变集合: 用不变的集合进行防御性编程和性能提升。
- 新集合类型: multisets, multimaps, tables,等
- 强大的集合工具类: 提供java.util.Collections中没有的集合工具
- 扩展工具类: 让实现和扩展集合类变得更容易, 比如创建Collection的装饰器, 或实现迭代器
各种功能
- 只读设置
- 函数式编程:过滤器
- 函数式编程:转换
- 组合式函数编程
- 加入约束: 非空、 长度验证
- 集合操作: 交集、 差集、 并集
- Multiset: 无序可重复,可计算个数
- Multimap key可以重复
- BiMap: 双向Map(bidirectional Map) 键与值不能重复
- 双键的Map —>Table —->rowKey+columnKye+value
package com.guava;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import com.google.common.collect.*;
import org.junit.Test;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.Sets.SetView;
import com.google.common.collect.Table.Cell;
public class GuavaDemo {
//双键的Map -->Table --->rowKey+columnKye+value
@Test
public void testGuava10(){
Table<String, String, Integer> table = HashBasedTable.create();
table.put("jack", "java", 80);
table.put("tom", "php", 70);
table.put("bin", "java", 59);
table.put("lily", "ui", 98);
Set<Cell<String,String,Integer>> cells = table.cellSet();
for(Cell c: cells){
System.out.println(c.getRowKey()+"-"+c.getColumnKey()+"-"+c.getValue());
}
//jack-java-80
//tom-php-70
//bin-java-59
//lily-ui-98
}
//BiMap:双向Map(bidirectional Map) 键与值不能重复
@Test
public void testGuava9(){
BiMap<String, String> map = HashBiMap.create();
map.put("finally_test", "18201583398");
map.put("bin_test", "18388881521");
String name = map.inverse().get("18201583398"); //通过value取key
System.out.println(name);
System.out.println(map.inverse().inverse()==map); //true
}
// Multimap:key可重复
@Test
public void testGuava8() {
Map<String,String> map = new HashMap<>();
map.put("Java从入门到精通", "bin");
map.put("Android从入门到精通", "bin");
map.put("PHP从入门到精通", "jack");
map.put("笑看人生", "vince");
Multimap<String, String> mmap = ArrayListMultimap.create();
Iterator<Map.Entry<String, String>> iter = map.entrySet().iterator();
while(iter.hasNext()){
Map.Entry<String, String> entry = iter.next();
mmap.put(entry.getValue(), entry.getKey());
}
Set<String> keySet = mmap.keySet();
for(String key: keySet){
Collection<String> values = mmap.get(key);
System.out.println(key+"->"+values);
}
//bin->[Java从入门到精通, Android从入门到精通]
//vince->[笑看人生]
//jack->[PHP从入门到精通]
}
// Multiset:无序可重复
@Test
public void testGuava7() {
String s = "good good study day day up";
String[] ss = s.split(" ");
HashMultiset<String> set = HashMultiset.create();
for (String str : ss) {
set.add(str);
}
Set<String> set2 = set.elementSet();
for (String str : set2) {
System.out.println(str + ":" + set.count(str));
}
//study:1
//up:1
//good:2
//day:2
}
// 集合操作:交集、差集、并集
@Test
public void testGuava6() {
Set<Integer> set1 = Sets.newHashSet(1, 2, 3);
Set<Integer> set2 = Sets.newHashSet(3, 4, 5);
// 交集
SetView<Integer> v1 = Sets.intersection(set1, set2);
// v1.forEach(System.out::println);
// 差集
SetView<Integer> v2 = Sets.difference(set1, set2);
// v2.forEach(System.out::println);
// 并集
SetView<Integer> v3 = Sets.union(set1, set2);
v3.forEach(System.out::println);
}
/**
* 加入约束:非空、长度验证
*/
@Test
public void testGuava5() {
// Set<String> set = Sets.newHashSet();
// 14版可用
// Constraint<String> constraint = new Constraint<>(){
// @Override
// public String checkElement(String element){
//
// }
// }
//检查参数
// Preconditions.checkArgument(expression);
// Preconditions.checkNotNull(reference)
}
/**
* 组合式函数
*/
@Test
public void testGuava4() {
List<String> list = Lists.newArrayList("java", "php", "jack", "h5", "javascript");
Function<String, String> f1 = new Function<String, String>() {
@Override
public String apply(String t) {
return t.length() > 4 ? t.substring(0, 4) : t;
}
};
Function<String, String> f2 = new Function<String, String>() {
@Override
public String apply(String t) {
return t.toUpperCase();
}
};
Function<String, String> f = Functions.compose(f1, f2);
Collection<String> coll = Collections2.transform(list, f);
coll.forEach(System.out::println);
// System.out.println(list);
// list=list.stream().filter((l)->(l.length()>=4)).map((l)->(l.toUpperCase())).collect(Collectors.toList());
// System.out.println(list);
}
/**
* 转换
*/
@Test
public void testGuava3() {
Set<Long> timeSet = Sets.newHashSet(20121212L, 20170520L, 20160808L);
Collection<String> timeCollect = Collections2.transform(timeSet,
(e) -> new SimpleDateFormat("yyyy-MM-dd").format(e));
timeCollect.forEach(System.out::println);
}
/**
* 过滤器
*/
@Test
public void testGuava2() {
List<String> list = Lists.newArrayList("java", "php", "jack", "h5", "javascript");
Collection<String> result = Collections2.filter(list, (e) -> e.startsWith("j"));
result.forEach(System.out::println);
// List<String> li= Arrays.asList("java", "php", "jack", "h5", "javascript");
// li= li.stream().filter((e) -> (e.startsWith("j"))).collect(Collectors.toList());
// System.out.println(li);
}
/**
* 设置 只读
*/
@Test
public void testGuava1() {
System.out.println("test guava");
// List<String> list = Arrays.asList("jack","tom","lily","bin");
// list.add("vince");
List<String> list = new ArrayList<>();
list.add("jack");
list.add("tom");
list.add("lily");
list.add("bin");
//变为只读
// List<String> readList = Collections.unmodifiableList(list);
// readList.add("vince");
//guava实现只读
ImmutableList<String> iList = ImmutableList.of("jack","tom","lily","bin");
iList.add("vince");
}
}