Java8 学习笔记(二) —— Stream API

这里的Stream非io流,简单的说就是使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象

	/*
	 * 一、Stream API 的操作步骤:
	 * 1. 创建 Stream
	 * 2. 中间操作
	 * 3. 终止操作(终端操作)
	 */
	public static void main(String[] args) {
		//1. Collection 提供了两个方法  stream() 与 parallelStream()
		List list = new ArrayList<>();
		Stream stream = list.stream(); //获取一个顺序流(串行流)
		Stream parallelStream = list.parallelStream(); //获取一个并行流
		
		//2. 通过 Arrays 中的 stream() 获取一个数组流
		Integer[] nums = new Integer[10];
		Stream stream1 = Arrays.stream(nums);
		
		//3. 通过 Stream 类中静态方法 of(T...t)
		Stream stream2 = Stream.of(1,2,3,4,5,6);
		
		//4. 创建无限流(迭代)
		//Stream.iterate的第一个参数可以看做是x的初始值
		//limit就是所谓的中间操作,如果不加中间操作,则会无穷输出
		//forEach就是指终止操作,不加终止操作,创建的Stream就无任何意义
		Stream stream3 = Stream.iterate(0, (x) -> x + 2).limit(10);
		stream3.forEach((x)-> System.out.println(x));
		//stream3.forEach(System.out::println); //简单写法
		
		//5. 创建无限流(生成)
		Stream stream4 = Stream.generate(Math::random).limit(2);
		stream4.forEach(System.out::println);
		
	}

Stream 中间操作

public class Tester {
	
	
	List emps = Arrays.asList(
			//Employee(int id, String name, int age, double salary)
			new Employee(102, "李四", 59, 6666.66),
			new Employee(101, "张三", 18, 9999.99),
			new Employee(103, "王五", 28, 3333.33),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(105, "田七", 38, 5555.55)
	);
	
	/*
	 * 中间操作有哪些?
	 * filter:接收 Lambda , 从流中排除某些元素
	 * limit(n):截断流,使其元素不超过n个数量
	 * skip(n):跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
	 * distinct:通过流所生成元素的 hashCode() 和 equals()去除重复元素
	 * map:遍历集合,返回新的集合
	 * flatMap:同map,只不过参数有一定特殊性,具体看实例代码
	 * sorted()——自然排序,即按实现Comparable类后的compareTo方法进行排序
	 * sorted(Comparator com)——定制排序
	 */

}
	//filter
	@Test
	public void filterTest(){
		//emps.stream()返回的是一个新流,不会对源数据emps产生任何影响
		Stream stream = emps.stream()
				.filter((e) -> {
					System.out.println(e.getName());
					return e.getAge() > 20;
				}); 
		//如果没有终止操作,中间操作是不会执行的,例如不会打印filter中的信息,这种方式被称为“惰性求值”
		stream.forEach(System.out::println);
	}
#控制台
李四 #这个是filter中的打印
Employee [id=102, name=李四, age=59, salary=6666.66] #这个是forEach中的打印,过滤后的实际结果
张三 
王五
Employee [id=103, name=王五, age=28, salary=3333.33]
赵六
赵六
赵六
田七
Employee [id=105, name=田七, age=38, salary=5555.55]
	//limit测试
	@Test
	public void limitTest(){
		emps.stream()
		//.filter((e) -> e.getAge() > 20)  //先过滤,在limit
		.limit(3)                        
		.forEach(System.out::println);
	}
#控制台
Employee [id=102, name=李四, age=59, salary=6666.66]
Employee [id=101, name=张三, age=18, salary=9999.99]
Employee [id=103, name=王五, age=28, salary=3333.33]
	//skip测试
	@Test
	public void skipTest(){
		emps.stream()
			.skip(3)
			.forEach(System.out::println);
	}
#控制台
Employee [id=104, name=赵六, age=8, salary=7777.77]
Employee [id=104, name=赵六, age=8, salary=7777.77]
Employee [id=104, name=赵六, age=8, salary=7777.77]
Employee [id=105, name=田七, age=38, salary=5555.55]
	//distinct测试
	@Test
	public void distinctTest(){
		emps.stream()
			.distinct()        //Employee必须重写hashCode和equals,否则去重无效
			.forEach(System.out::println);
	}
#控制台
Employee [id=102, name=李四, age=59, salary=6666.66]
Employee [id=101, name=张三, age=18, salary=9999.99]
Employee [id=103, name=王五, age=28, salary=3333.33]
Employee [id=104, name=赵六, age=8, salary=7777.77]
Employee [id=105, name=田七, age=38, salary=5555.55]
	//map测试
	@Test
	public void mapTest(){
		
		//遍历集合中的Employee,返回新的集合,集合变为List
		Stream map = emps.stream().map((e)-> e.getName());
		map.forEach(System.out::println);
		
		//修改age,返回Employee
		Stream map2 = emps.stream().map((e) -> {e.setAge(new Random().nextInt(50));return e;});
		map2.forEach(System.out::println);
		
		//简写版
		//emps.stream().map((e)-> e.getName()).forEach(System.out::println);    
		//emps.stream().map(Employee::getName).forEach(System.out::println);   //更简单的写法
		//emps.stream().map((e) -> {e.setAge(new Random().nextInt(50));return e;}).forEach(System.out::println);
			
	}
#控制台
李四
张三
王五
赵六
赵六
赵六
田七
	//flatMap测试
	@Test
	public void flatMapTest() {
		List list = Arrays.asList("abc");  //第一个用来遍历的集合
		//flatMap的入参为:Function>
		list.stream().flatMap((str) -> { //遍历第一个集合
			List list2 = new ArrayList<>();
			for (Character character : str.toCharArray()) {
				list2.add(character);  //对第一集合的String拆分成Character
			}
			return list2.stream(); //将List作为流返回
		}).forEach(System.out::println); //这里实际打印的是list2,这就是同map的区别
		
		//将list2封装成一个方法后,更简单的写法
		list.stream().flatMap(this::filterCharacter).forEach(System.out::println);
	}
	
	//拆分string,返回char
	private Stream filterCharacter(String str){
		List list = new ArrayList<>();
		for (Character ch : str.toCharArray()) {
			list.add(ch);
		}
		return list.stream();
	}
#控制台
a
b
c
	//sorted测试
	@Test
	public void testSorted(){
		
		//自然排序,按字符串默认实现排序
		emps.stream()
			.map(Employee::getName)
			.sorted()
			.forEach(System.out::println);
		
		//定制排序
		emps.stream()
			.sorted((x, y) -> {
				if(x.getAge() == y.getAge()){
					return x.getName().compareTo(y.getName());
				}else{
					return Integer.compare(x.getAge(), y.getAge());
				}
			}).forEach(System.out::println);
	}
#控制台输出
张三
李四
王五
田七
赵六
赵六
赵六
Employee [id=104, name=赵六, age=8, salary=7777.77]
Employee [id=104, name=赵六, age=8, salary=7777.77]
Employee [id=104, name=赵六, age=8, salary=7777.77]
Employee [id=101, name=张三, age=18, salary=9999.99]
Employee [id=103, name=王五, age=28, salary=3333.33]
Employee [id=105, name=田七, age=38, salary=5555.55]
Employee [id=102, name=李四, age=59, salary=6666.66]

Stream 终止操作

public class Tester2 {
	
	
	List emps = Arrays.asList(
			//Employee(int id, String name, int age, double salary)
			new Employee(102, "李四", 59, 6666.66),
			new Employee(101, "张三", 18, 9999.99),
			new Employee(103, "王五", 28, 3333.33),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(105, "田七", 38, 5555.55)
	);
	
	/*
	 * 终止操作有哪些?
	 * allMatch:检查是否匹配所有元素
	 * anyMatch:检查是否至少匹配一个元素
	 * noneMatch:检查是否没有匹配的元素
	 * findFirst:返回第一个元素
	 * findAny:返回当前流中的任意元素
	 * count:返回流中元素的总个数
	 * max:返回流中最大值
	 * min:返回流中最小值
	 * forEach:内部迭代,遍历元素
	 */
	
	@Test
	public void test1() {
		boolean b1 = emps.stream().allMatch((e) -> e.getAge() > 20); //检查否全部的年龄都超过20
		System.out.println(b1); //返回false
		
		boolean b2 = emps.stream().anyMatch((e) -> e.getAge() > 20); //检查至少有一条年龄超过20
		System.out.println(b2); //返回true
		
		boolean b3 = emps.stream().noneMatch((e) -> e.getAge() > 60); //超过60岁,没有被匹配到的
		System.out.println(b3); //超过60岁的一个也没有,所有未匹配上,返回true
		
		//找出第一个元素,Optional是什么,后面会讲,这里只需要知道结果有可能为null,就会返回Optional
		Optional op = emps.stream().findFirst(); 
		Employee employee = op.get();
		
		Optional op2 = emps.stream().findAny();  //随机找出一个元素
		Employee employee2 = op2.get();
		
		long count = emps.stream().count();  //总个数
		
		Optional op3 = emps.stream().max((e1,e2) -> Integer.compare(e1.getAge(), e2.getAge())); //最大值
		Employee employee3 = op3.get(); 
		
		Optional op4 = emps.stream().map(Employee::getSalary).min(Double::compare);   //取出salary,然后求最小值
		Double dou = op4.get();
		
		emps.stream().forEach(System.out::println);  //遍历元素
	}
}

 

你可能感兴趣的:(java8)