疯狂java——集合、泛型、Stream

前言

之前我们学习了使用数组来保存多个对象,但数组长度不可变化,如果需要保存数量变化的数据,数组就有点无能为力了,所以我们需要使用集合。

List 、Set、 Map
List:有序的集合,可以重复
Set:无序的集合,不可重复
Map: key-value
在这里插入图片描述
由图中可以看出,List和Set的父接口都是Collection

集合类和数组的不一样:
数组元素既可以是基本类型的值,也可以是对象(实际上保存的是对象的引用变量);而集合里只能存放引用变量
集合重写了equals()和hashcode()方法:
在这里插入图片描述
方法
测试Collection接口的常用方法:

//测试collection接口的常用方法
public class Demo1 {
	/**
	 * 泛型是jdk5.0才出现的
	 * Collection<String> coll=new ArrayList<String>();
	 * jdk1.7之后
	 * Collection<String> coll=new ArrayList<>();
	 * @param args
	 */

	public static void main(String[] args) {
		//Collection<Integer> coll1=new ArrayList<>();
		//coll1.add(1); //自动封箱
		
		Collection<String> coll=new ArrayList<String>();
		//按顺序添加
		System.out.println(coll.isEmpty());  //true
		coll.add("hello");
		coll.add("abc");
		coll.add("123");
		// boolean isEmpty(): 返回集合是否为空 当集合长度为0 时返回 true ,否则返回 false
		boolean b=coll.isEmpty();
		System.out.println(b);   //false
		// int size(): 该方法返回集合里元素的个数。
		System.out.println(coll.size());
		// boolean contains(Object o): 返回集合里是否包含指定元素
		System.out.println(coll.contains("hello"));   //true
		// boolean remove(Object 0): 除集合中的指定元素。
		coll.remove("hello");
		System.out.println(coll.size());  //2
		coll.clear();
		System.out.println(coll.isEmpty());   //true
	}

}

遍历集合元素的三种方式:

        Collection<String> coll=new ArrayList<String>();
		System.out.println(coll.isEmpty());  //true
		coll.add("hello");
		coll.add("abc");
		coll.add("123");
		
		//第一种方法:增强for循环
		for(String str:coll) {
			System.out.println(str);
		}
		System.out.println("==========");
		//第二种方法:迭代器
		Iterator<String> it=coll.iterator();
		//当前容器中是否有元素
		while(it.hasNext()) {
			String str=it.next();
			System.out.println(str);
		}
		System.out.println("==========");
		//第三种:lambda
		coll.forEach(a->System.out.println(a));

和集合相关的方法:

//和集合相关的方法
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Collection<String> c1=new ArrayList<>();
		c1.add("c");
		c1.add("c++");
		c1.add("java");
		Collection<String> c2=new ArrayList<>();
		c2.add("jsp");
		c2.add("php");
		c2.add("java");//可以添加进去,因为List有序
		
		// boolean containsAll(Collection c):集合里是否包含集合c里的所有元素。
		boolean b=c1.containsAll(c2);
		System.out.println(b);
		// boolean addAll(Collection c) 该方法把集合c 里的所有元素添加到指定集合里。
		boolean b2=c1.addAll(c2);
		c1.forEach(str->System.out.println(str));
		//c1.removeAll(c2);
		c1.forEach(str->System.out.println(str));
	}

List
默认初始容量:10
在这里插入图片描述
ArrayList底层的实现是线性表,实际是数组:
在这里插入图片描述
transient关键字修饰的变量不会被序列化。

下面程序示范了 List 集合的常规用法。

        List<String> list=new ArrayList<>();
		list.add("hello");
		list.add(0,"abc");
		list.forEach(str->System.out.println(str));
		list.set(1, "111");
		list.forEach(str->System.out.println(str));
		list.remove(0);
		list.forEach(str->System.out.println(str));
		System.out.println("============");
		//遍历
		for(int i=0;i<list.size();i++) {
			System.out.println(list.get(i));
		}

集合和数组的相互转换及排序

//集合转成数组
	public static void test1() {
		List<String> list=new ArrayList<>();
		list.add("hello");
	    list.add(0,"abc");
	    List<Integer> list2=new ArrayList<>();
		list2.add(1);
		list2.add(2);
		Object[] obj=list2.toArray();
		int sum=0;
		for(Object object:obj) {
			sum+=(Integer)object;
		}
		//经常用的方法
		Integer[] li=list2.toArray(new Integer[list2.size()]);
		for(Integer i:li) {
			sum+=i;
		}
		
		//对数组排序
		//默认升序
		Arrays.sort(li);
		System.out.println(Arrays.toString(li));
		
		String[] strs=new String[list.size()];
		Arrays.sort(list.toArray(strs));
		System.out.println(Arrays.toString(strs));	
	}

	static Comparator<String> com=new Comparator<String>() {
		public int compare(String o1, String o2) {
			return o1.length()-o2.length();
		}	
	};

	//数组转成集合  asList()
	//给集合排序,使用的是  	Collections的sort方法  //底层还是Arrays.sort()
	public static void test2() {
		String[] str= {"hello","abc","bde"};
		//数组转成集合
		List<String> list=Arrays.asList(str);
		
		//集合的排序
		Collections.sort(list);  //底层还是Arrays.sort()
		System.out.println(list);
		
		//自定义排序规则:按长度排序
		//Collections.sort(list,com);
		//匿名表达式的形式
		Collections.sort(list,(o1,o2)->o1.length()-o2.length());
		System.out.println(list);
	}

练习:按照学生成绩排序
1.定义Student类
两个变量:name,score
方法:
2.定义集合,3个student对象,添加到集合
3.使用sort方法排序,排序是指定排序规则
4.输出排序后的集合

//方法一:
public class Student {
	private String name;
	private int score;
	public Student(){
		
	}
	public Student(String name, int score) {
		super();
		this.name = name;
		this.score = score;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getScore() {
		return score;
	}
	public void setScore(int score) {
		this.score = score;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", score=" + score + "]";
	}
	
}
//方法二:
public class Student2 implements Comparable<Student2>{

	private String name;
	private int score;
	public Student2(){
		
	}
	public Student2(String name, int score) {
		super();
		this.name = name;
		this.score = score;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getScore() {
		return score;
	}
	public void setScore(int score) {
		this.score = score;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", score=" + score + "]";
	}
	@Override
	public int compareTo(Student2 o) {
		
		return this.score-o.score;
	}
	
}
        List<Student> stuList = new ArrayList<>();
		stuList.add(new Student("admin",60));
		stuList.add(new Student("zhangsan",90));
		stuList.add(new Student("lisi",80));
		Collections.sort(stuList,
				(stu1,stu2)->stu1.getScore()-stu2.getScore());
		System.out.println(stuList);
		System.out.println("===========================");
		List<Student2> stuList2 = new ArrayList<>();
		stuList2.add(new Student2("admin",60));
		stuList2.add(new Student2("zhangsan",90));
		stuList2.add(new Student2("lisi",80));
		Collections.sort(stuList2);
		System.out.println(stuList2);

练习
实现ArrayList

//MyArray      (String)
class MyArray{
    //int size;//表示集合的元素个数
	//String[] strArray;
	private int size;
	private String[] strArray;
    //1.定义无参的构造方法  默认给数组10个
    public MyArray(){
    	strArray = new String[10];
    }
    //2.定义一个带参的构造方法
    public MyArray(int length){
    	strArray = new String[length];
    }
   /*3.add(String str);
	判断元素的个数和数组的长度之间的关系  size>=strArray 扩容
	添加元素
	size++;*/
    public void add(String str){
    	if(size>=strArray.length){
    		grow();
    	}
    	strArray[size]=str;
    	size++;
    }
		
    /*4.定义grow方法
	规则:数组长度的一半(如果数组长度为1 ,扩容应该是+1)*/
    private void grow(){
    	if(strArray.length<=1){
    		strArray = Arrays.copyOf(strArray, strArray.length+1);
    	}else{
    		strArray = Arrays.copyOf(strArray, strArray.length+strArray.length/2);
    	}
    }
    /*5.add(int index,String str)
	判断元素的个数和数组的长度之间的关系  size>=strArray 扩容
	当前的数组元素后移
	插入元素
	size++;*/
    public void add(int index,String str){
    	if(size>strArray.length){
    		grow();
    	}
    	
    	//{1,2,3}  index = 1      3 -  1
    	//{1,1,2,3}
    	System.arraycopy(strArray, index, strArray, index+1, size-index);
    	strArray[index] = str; 
    	size++;
    }
    /*6.remove(int index)
	当前的数组元素前移
	size--;*/
    public void remove(int index){
    	//{1,2,3}  index = 1     3    1-1  
    	//{1,3} 
    	System.arraycopy(strArray, index+1, strArray, index, size-index-1);
    	strArray[--size]=null;
    }
    //7.set(int index,String str):修改
    public void set(int index,String str){
    	strArray[index] = str;
    }
    /*8.get(int index):获取元素*/
    public String get(int index){
    	return strArray[index];
    }     
    /*9.size():返回集合中的元素个数*/
    public int size(){
    	return size;
    }
}


public class Demo {

	public static void main(String[] args) {
		MyArray arr = new MyArray();
		arr.add("hello");
		arr.add("abc");
		arr.add("admin");
		arr.remove(1);
		arr.set(1, "admin1111");
		arr.add(1,"222");
		for(int i = 0;i<arr.size();i++){
			System.out.println(arr.get(i));
		}
	}
}
	

泛型

什么是泛型?
java泛型设计原则:编译不出错,运行时不会出现ClassCastException


泛型基础

1.泛型类

在类上定义的泛型,在方法中也可以使用
class TestObj<T>{
    private T obj;
    private int age;
    private String name;
......
    
}

测试代码:(通过泛型定义变量的类型,比如老师工资和学生学号)

public class TestObj<T> {
	private T data;
	private String name;
	public TestObj() {
		
	}
	public TestObj(T data, String name) {
		super();
		this.data = data;
		this.name = name;
	}
	public T getData() {
		return data;
	}
	public void setData(T data) {
		this.data = data;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "TestObj [data=" + data + ", name=" + name + "]";
	}
	

}
        TestObj<String> stu=new TestObj<>();
		stu.setName("张三");
		stu.setData("201716122387");
		System.out.println(stu);
		TestObj<Float> emp=new TestObj<>();
		emp.setData(10000.231f);
		emp.setName("老师");
		System.out.println(emp);

结果:

TestObj [data=201716122387, name=张三]
TestObj [data=10000.231, name=老师]


2.泛型方法

   <T> void f(){}

方法返回类型前面有<>才是泛型方法
泛型方法所在的类不一定是泛型类

//输出任意数据类型的数组元素
	public static <T> void showData(T[] arr) {
		for(T t:arr) {
			System.out.println(t);
		}
	}
	public static void test3() {
		Integer[] num= {1,2,3};
		//必须是引用类型
		showData(num);
	}

结果:

1
2
3

3.泛型类派生出的子类:

  • 子类明确泛型类的类型参数变量,该子类就是一个普通类

  • 子类不明确泛型类的类型参数变量,该子类是一个泛型类

以接口为例:泛型接口

泛型接口:

   interface Demo<T>{}
interface Inter<T>{
	void show(T t);
}
class Im implements Inter<String>{

	@Override
	public void show(String t) {
		System.out.println(t);
		
	}
}
class Im2<T> implements Inter<T>{

	@Override
	public void show(T t) {
		System.out.println(t);		
	}	
}	
使用规则:
public class Demo3 {
	public static void main(String[] args) {
		Inter<String> i2= new Im();
		i2.show("hello");
		Inter<Integer> i3= new Im2<>();
		i3.show(1);
	}
}

4.泛型的使用-通配符 ? 表示任意数据类型

 public static void show(List<Object> list){
		for(Object obj : list){
			System.out.println(obj);
		}
	}
    List<Object>   和  List<String>不存在继承关系

5.设置通配符的上限List<? extends Animal> list
6.设置通配符的下限List<? super Number> list

public class Demo4 {
	public static void show(List<?> list){
		for(Object obj : list){
			System.out.println(obj);
		}
	}
	public static void test1(List<? extends Number> list){
		for(Number obj : list){
			System.out.println(obj);
		}
	}
	public static void test2(List<? super Number> list){
		for(Object obj : list){
			System.out.println(obj);
		}
	}
	public static void main(String[] args) {
		List<Object> list = new ArrayList<>();
		//List<Integer> list = new ArrayList<>();
		list.add(1);
		list.add(2);
		test2(list);
		/*List<String> list = new ArrayList<>();
		list.add("abc");
		list.add("hello");
		list.add("123");
		show(list);*/

	}

}


通配符的错误使用

class A<?>{}
public <?> void t(List<?> list){}
List<?> list = new ArrayList<?>(); //错在ArrayList<?>()


Stream

Stream:和io没有任何关系

流式思想:像生产流水线一样,一个操作接一个操作。

使用流操作集合更高效

2.stream的特性
1.stream不存储数据
2.stream不改变源数据
3.stream的延迟执行特性

3.使用Stream流的步骤:数据源→转换成流→操作1→操作2→……

4.数据源(source):可以是集合、数组等。

5.获取流:

 // List
 list.stream();
 // 数组
 Stream.of();

6.常用方法
Stream只能被使用一次,如果还想使用,必须重新获取流。
如果不重新获取,会得到异常:stream has already been operated upon or closed

1.filter 方法用于通过设置的条件过滤出元素
	
2.map 方法用于映射每个元素到对应的结果

3.limit 方法用于获取指定数量的流

4.跳过前n个stream.skip
	
5.流的连接Stream.concat(stream1,stream2)

6.回数量count

7.可以把流转换为 List 集合类型:collect(Collectors.toList());

8.求和的方法reduce(0, (x, y) -> x + y)

9.去重distinct()

10.排序:sorted()

返回的是流,就可以用foreach()

public class Demo5 {
    public static void test2() {
    	Stream<Integer> stream=Stream.of(1,2,3,4,5,6,7);
    	Stream<Integer> numStream=stream.filter(e->e%2!=0);//有延迟
    	//返回的是流,就可以用foreach
    	numStream.forEach(e->{
    		System.out.println("=======");
    	System.out.println(e);
    	});
    	System.out.println("filter");
    	
    	stream=Stream.of(1,2,3,4);
    	stream.map(e->e*e).forEach(e->System.out.println(e));
    	stream.limit(3).forEach(e->System.out.println(e));
    	System.out.println("=======");
    	//跳过
    	stream.skip(3).forEach(e->System.out.println(e));
    	
    }
    public static void test() {
    	List<String> listStr=new ArrayList<>();
		listStr.add("hi");
		listStr.add("heelo");
		
		Integer[] num= {1,2,3,4};
		Stream<String> s=listStr.stream();
		Stream<Integer> i=Stream.of(num);
		
		Stream.concat(s, i).forEach(e->System.out.println(e));
		
		//报异常stream has already been operated upon or closed
		i.forEach(e->System.out.println(e));
		i.forEach(e->System.out.println(e));  
    }
    
    public static void test3() {
    	Stream<Integer> stream=Stream.of(1,2,3,4,5,6,7);
    	System.out.println(stream.count());
    	List<Integer> i=stream.collect(Collectors.toList());
    	System.out.println(i);
    	//0相当于sum初始值
    	System.out.println(stream.reduce(0,(x,y)->x+y));
    	stream=Stream.of(1,2,1,3);
    	stream.distinct().forEach(e->System.out.println(e));
    	stream=Stream.of(2,5,3);
    	stream.sorted().forEach(e->System.out.println(e));
    	//从大到小排
    	stream.sorted((x,y)->y-x).forEach(e->System.out.println(e));
    }
}

练习
1.有如下整数1,-2,-3,4,-5,使用Stream取元素绝对值并打印

 stream.map(e->Math.abs(e)).forEach(System.out::print);

2.给定一个数字列表,如何返回一个由每个数的平方构成的列表
给定【1,2,3,4,5】, 应该返回【1,4,9,16,25】。

stream.map(e-> e*e).forEach(System.out::print);

3.有如下7个元素黄药师,冯蘅,郭靖,黄蓉,郭芙,郭襄,郭破虏,
使用Stream将以郭字开头的元素存入新集合

stream.filter(e->e.starWith("郭")).colect(Colectors.toList());

4.已知ArrayList集合中有如下元素{陈玄风、梅超风、陆乘风、曲灵风、
武眠风、冯默风、罗玉风},

使用Stream
1、取出前2个元素并在控制台打印输出。

stream.limit(3).forEach(System.out::print);

2、取出后2个元素并在控制台打印输出。

stream.skip(list.size()-2).forEach(System.out::print);

5.怎样用 map 和 reduce 方法数一数流中有多少个Employee
List emps = Arrays.asList(
new Employee(102, “李四”, 59),
new Employee(101, “张三”, 18),
new Employee(103, “王五”, 28),
new Employee(104, “赵六”, 8),
new Employee(105, “田七”, 38)
);

stream.map(e->1).reduce(0,(x,y)->x+y)

6.找出2011年发生的所有交易, 并按交易额排序(从低到高)

class Transaction {   
    private int year;   //交易时间
    private int value;  //交易额
   方法。。。。
	List<Transaction> transactions =Arrays.asList(
                new Transaction(2011, 300),
         	new Transaction(2012, 1000),
         	new Transaction(2011, 400),
                new Transaction(2012, 710),
		new Transaction(2011, 200),
                new Transaction(2012, 700),
                new Transaction(2012, 950)
        );
    
stream.filter(e->e.getYear()==2011).
       sorted((t1,t2)->t1.getValue()-t2.getValue()).forEach(....);

集合

List集合的实现类

LinkedListArrayList都是线程不安全的
Vector是线程安全的

List<String> list = 
			new LinkedList<>();	
List<String> v = new Vector<>();

练习

class LinkList{
		private int size = 0; // 节点个数
		private Node first; // 第一个节点
		private Node last; // 最后一个节点
		//无参构造方法
	    public LinkList() {
	    	
	    }
	        //添加元素
		public void add(String str) {
			Node node=new Node(null,str,null);
			if(size==0) {
				this.first=node;
				this.last=node;
			}else {
				 this.last.next=node;
				 node.prev=this.last;
				 this.last=node;
			}
			size++;
		}
	        //插入
		//插入时先写最后插入
		public void add(int index, String str) {
			//最后,this.add()
			if(index == size){
				this.add(str);
				return;
			}
			Node node = new Node(null,str,null);
			if(index==0){
				//在最前边
				node.next = this.first;
				this.first.prev = node;
				this.first = node;
			}else{
				Node node1 = this.getNode(index);
				node1.prev.next = node;
				node.prev = node1.prev;
				node.next = node1;
				node1.prev = node;
			}
			size++;

		}
	        // 获取指定位置的节点
		 Node getNode(int index) {
			Node node=this.first;
			for(int i=0;i<index;i++) {
				node=node.next;
			}
			return node;
			
			
		}
	        //删除
		public void remove(int index) {
			if(index == 0){
				this.first.next.prev = null;
				this.first = this.first.next;
			}else if(index == size-1){
				this.last.prev.next = null;
				this.last = this.last.prev;
			}else{
				Node node = this.getNode(index);
				node.prev.next = node.next;
				node.next.prev = node.prev;
			}
			size--;
		}
	        //返回节点的内容
		public String get(int index){
			return this.getNode(index).data;
			
		}
		// 返回元素个数
		public int size(){
			return size;
		      
		}
		//利用节点存储数据
		private class Node {

			Node prev; // 上一个节点
			String data; // 元素
			Node next; // 下一个节点

			public Node(Node prev, String data, Node next) {
				super();
				this.prev = prev;
				this.data = data;
				this.next = next;
			}

		}
		
	
}
public class DemoLinkedList {
	public static void main(String[] args) {
		LinkList linkList=new LinkList();
		linkList.add(0,"hello");
		System.out.println(linkList.size());
		linkList.add(1,"success");
		linkList.add(2,"su");
		System.out.println(linkList.get(0));
		System.out.println(linkList.get(1));
		System.out.println(linkList.get(2));
		linkList.remove(2);
		System.out.println(linkList.get(0));
		System.out.println(linkList.get(1));
		
	}

}

运行结果:

1
hello
success
su
hello
success

Set集合
不重复:先判断hashCode(); 相同,还要判断equals()方法,如果返回true表示一个对象,否则是不同对象

HashSet和TreeSet
HashSet基于HashMap的实现
HashSet的元素是map中的key,value值对应的是一个常量

HashSet:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public class Demo7 {
	public static void test(){
		Set<String> set = 
				new HashSet<>();
		set.add("张三");
		set.add("张三");
		set.add("李四");
		set.add("王五");
		set.remove("王五");
		set.forEach(System.out::println);
	}
	public static void test2(){
		Set<Emp> set = new HashSet<>();
		set.add(new Emp("张三"));
		set.add(new Emp("张三"));
		set.add(new Emp("李四"));
		set.add(new Emp("王五"));
		set.forEach(System.out::println);  
		//Emp [name=张三]
        //Emp [name=李四]
        //Emp [name=王五]
	}
	public static void main(String[] args) {
		test2();
		
	}

}
public class Emp {
	private String id;
	private String name;
	public Emp(){
		
	}
	public Emp(String name){
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	


	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		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;
		Emp other = (Emp) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	@Override
	public String toString() {
		return "Emp [name=" + name + "]";
	}
	
}

TreeSet的元素必须是有排序规则的对象,否则会运行时异常
在这里插入图片描述

public static void test(){
		TreeSet<String> set = new TreeSet<>();
		set.add("abc");
		set.add("bed");
		set.add("avs");
		set.forEach(System.out::println);
	}
	public static void test2(){
		TreeSet<Emp> set = new TreeSet<>(
				(emp1,emp2)->
				emp1.getName().length()-emp2.getName().length());
		set.add(new Emp("admin"));
		set.add(new Emp("baf"));
		set.add(new Emp("abmin333"));
		
		set.forEach(System.out::println);
	}

Map集合

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值