摘记一下最近敲的关于集合方面的Demo,会陆续做成博客记录下来的。
这次摘记的是:
- Collections基本的遍历方式:
- 传统的
foreach(T t : Collections c){ ... }
- Collections自带的Lambda遍历方式:
Collections c.forEach(obj-> ...)
Iterator
对象进行遍历
- 传统的
Set
接口的四种常见实现类:- HashSet 无序并且性能比TreeSet高效,适用于基本的添加、查询元素的场合。
- TreeSet 采用的二叉树的数据结构,需要采用红黑树算法维护数据的排序,对Set的数据类型有要求(需要实现Comparable接口或者是在TreeSet构造的时候定义排序),性能较HashSet低效,比较适用于需要保持排序的场景。
- LinkedHashSet 采用的链表维护插入元素的顺序,其他与HashSet无太大差异,性能较HashSet略低(链表开销)
- EnumSet 这四种常见Set实现类中最高效的,采用的是位向量的数据结构存储元素(存储高效、紧凑),要求存储元素必须是一个Enum(约束大),适用于枚举值执行批量操作的场景
这里补充说明下,上述的四种Set都是非线程安全的,即需要使用代码同步机制保证多线程访问的安全性。想使用线程安全的Set,可采用_synchronizedSortedSet_(线程安全)。
以下为笔者学习时采用的Demo,笔者将一些心得记录放在了Demo的注释中,如果有dalao可以指点下小弟,欢迎私信:[email protected]
public class SetDemo {
static SetDemo mine = new SetDemo();
/**
* 这是一般的Lambda表达式遍历集合
*/
public void LambdaEx() {
Collection<Integer> i = new HashSet<Integer>();
i.add(1);
i.add(2);
i.add(3);
i.add(4);
i.forEach(obj -> System.out.println(obj));
}
/**
* 这是Lambda遍历Iterator对象
*/
public void LambdaIterator() {
Collection<Integer> i = new HashSet<Integer>();
i.add(1);
i.add(2);
i.add(3);
i.add(4);
Iterator<Integer> it = i.iterator();
// 这是传统的使用Iterator对象循环遍历集合
// while(it.hasNext()) {
// int num = (Integer)it.next();
// if(num == 3) {
// it.remove();
// }
// System.out.println(num);
// }
// 利用Lambda表达式循环输出对象
it.forEachRemaining(obj -> System.out.println(obj));
}
/**
* 这个是用来显示Java 8中的IntStream LongStream DoubleStream等流式接口
*/
public void IntLongDoubleStream() {
IntStream is = IntStream.builder().add(1).add(13).add(20).add(18).build();
Collection<Integer> c = new HashSet<Integer>();
c.add(1);
c.add(2);
c.add(3);
c.add(4);
// // 下面的聚集方法的代码每次只能被调用一,就是下面的max() min() 等只能同时调用一个
// System.out.println("MAX: "+ is.max().getAsInt());
// System.out.println("MIN: "+is.min().getAsInt());
// // 这个是用于匹配is中的所有元素是否都满足所述的要求
// System.out.println("is 中所有元素的平方是否大于20:"+is.allMatch(ele->ele*ele>20));
// // 这是对is中所有的对象进行修改
// IntStream newIs = is.map(ele->ele*2);
// newIs.forEach(ele->System.out.println(ele));
c.stream().filter(ele -> ele > 4);
}
/**
* TreeSet Demo代码 TreeSet
* 会自动对插入的元素进行排序,倘若数据是使用的自定义的类型,那么那个类型需要实现Comparable接口(compareTo方法) TreeSet
* 实际上应该是一颗完全二叉树,并且对插入的数据进行修改的话可能会导致Set混乱,因为会出现无序并且无法找到元素的情况
* 读出数据的时候会采用中序遍历的方式进行读出
*/
public void TreeSetDemo() {
// 默认的,使用基本的数字类型的会按照递增的顺序排列
TreeSet<M> tSet = new TreeSet<M>((o1, o2) -> {
M m1 = (M) o1;
M m2 = (M) o2;
// 递减的排序
return m1.age > m2.age ? -1 : m1.age < m2.age ? 1 : 0;
});
// 插入三条数据
tSet.add(new M(5));
tSet.add(new M(-3));
tSet.add(new M(9));
System.out.println(tSet);
}
/**
* HashSet Demo代码
* HashSet保存元素是无序且唯一的,如果企图修改其中的元素会导致Set进入混乱的状态,进而Set无法识别对应的元素,无法精确定位元素
* 倘若需要重写equals方法切近最后也重写hashCode方法,因为equals方法相等的对象,它们的hashCode也应该相同。而HashSet需要利用这两个函数进行重复的判断
*/
public void HashSetDemo() {
Set<R> hSet = new HashSet<R>();
hSet.add(new R(5));
hSet.add(new R(-3));
hSet.add(new R(9));
hSet.add(new R(-2));
hSet.add(new R(3));
// 初始状态hSet
System.out.println(hSet);
// 这里可以给所引起加上一个type
Iterator<R> it = hSet.iterator();
// 做了一个很危险的操作,将Set的第一个元素的值修改为-3
R first = (R) it.next();
first.count = -3;
// 修改后状态hSet
System.out.println(hSet);
System.out.println("hSet 是否包含-2的元素? " + hSet.contains(new R(-2)));
// 试图移除这个R(-3)对象
hSet.remove(new R(-3));
System.out.println(hSet);
System.out.println("hSet 是否包含-3的元素? " + hSet.contains(new R(-3)));
System.out.println("hSet 是否包含-2的元素? " + hSet.contains(new R(-2)));
}
/**
* LinkedHashSet相较于HashSet的不同是,LinkedHashSet会以链表的形式维护插入元素的顺序
*/
public void LinkedHashSetDemo() {
Set<String> lSet = new LinkedHashSet<String>();
// 重点是观察其插入是具有有序性的,即LinkedHashSet会维持元素插入的顺序
lSet.add("t1");
lSet.add("t2");
System.out.println(lSet);
// 移除再重新插入,顺序会改变
lSet.remove("t1");
lSet.add("t1");
System.out.println(lSet);
}
/**
* EnumSet Demo代码 EnumSet 采用的是位向量来存储变量,进行批量操作(ContainsAll retainAll()方法)特别合适
* EnumSet 不允许插入null值
*/
public void EnumSetDemo() {
// 以一个枚举类型创建一个EnumSet,此时会以枚举的所有值填充此EnumSet
EnumSet<Season> eSet = EnumSet.allOf(Season.class);
// 以一个枚举类型创建一个空的EnumSet,这里只是单纯地指定了枚举的类型
EnumSet<Season> eSet2 = EnumSet.noneOf(Season.class);
// 比较下两种EnumSet的区别
System.out.println(eSet);
System.out.println(eSet2);
// 试图插入一个枚举值
eSet2.add(Season.SPRING);
// 以指定的枚举值创建EnumSet
EnumSet<Season> eSet3 = EnumSet.of(Season.SPRING,Season.SUMMER);
// 以枚举类型中指定范围的值创建EnumSet
EnumSet<Season> eSet4 = EnumSet.range(Season.SPRING,Season.WINTER);
// eSet5 + eSet4 -> Season中所有的枚举值
EnumSet<Season> eSet5 = EnumSet.complementOf(eSet4);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
// Lambda遍历集合的方式
// mine.LambdaIterator();
// 使用Stream对象遍历集合的方式
// mine.IntLongDoubleStream();
// 常见的三种Set接口实现类
// mine.TreeSetDemo();
// mine.HashSetDemo();
// mine.LinkedHashSetDemo();
// mine.EnumSetDemo();
}
/**
* 用于演示TreeSet的类,该类未实现Comparable接口,而是将比较的方式在构建TreeSet的时候以构造函数的形式注入了
*
* @author Administrator
*
*/
class M {
int age = 0;
public M(int age) {
this.age = age;
}
public String toString() {
return String.format("M[ age: %d]", age);
}
}
/**
* 用于演示HashSet的类,关键在于重写equals和hashCode方法
* @author Administrator
*
*/
class R {
int count;
public R(int count) {
this.count = count;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return String.format("R[count:%d]", count);
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if (this == obj) {
return true;
}
if (obj != null && obj.getClass() == R.class) {
R r = (R) obj;
return this.count == r.count;
}
return false;
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return this.count;
// return super.hashCode();
}
}
/**
* 用于演示EnumSet的类
* @author Administrator
*
*/
enum Season{
SPRING,SUMMER,FAIL,WINTER
}
}