JDK8新特性 2W字总结的硬核知识

本文介绍了Lambda表达式的标准格式和使用,包括创建线程、方法引用、成员方法引用、静态方法引用、构造器引用和数组构造器引用。同时,讲解了链式编程的思想和在Java中的应用,如Stream流式计算及其常见操作。

一:Lambda 表达式

😀Lambda表达式的标准格式:由三部分组成

  • 1 : 一些参数
  • 2 : 一个箭头
  • 3 : 一段代码

格式:

( 参数列表 ) -> { 一些重写方法的代码 }

说明:

  • () : 接口中抽象方法的参数列表,没有参数,就空着;有参数就写出参数,多个参数使用逗号分隔
  • -> : 传递的意思,把参数传递给方法体 { }
  • { } : 重写接口的抽象方法的方法体

简写Lambda表达式格式:

  • 1:(参数列表):括号中参数列表的数据类型 可以省略不写
  • 2:(参数列表):括号中的参数如果只有一个,那么类型 和 ( ) 都可以省略
  • 3:{代码}:如果 { }中的代码只有一行,无论是否有返回值,都可以省略 { }, return ,分号
  • 注意事项:如果要省略 { }, return ,分号 ,必须一起省略,否则都不能省略

🤭光说不练 假把式 上代码

使用Lambda表达式创建线程
之前我们使用匿名内部类创建线程是这样子滴~
在这里插入图片描述
使用Lambda表达式替换匿名内部类实现 创建多线程
在这里插入图片描述
还可以再简写
在这里插入图片描述

Lambda表达式的优化:

😀1、方法引用

定义一个打印的函数式接口

//定义一个打印的函数式接口
@FunctionalInterface
interface Printable{
	//打印字符串的抽象方法
	public abstract void print(String s);
} 

Main方法

public class Demo1Print {
	/*方法参数传递Printable接口,对字符串打印输出
	 * */
	public static void printString(Printable p) {
		p.print("I Love Java");
	}
	public static void main(String[] args) {
		printString(s->System.out.println(s));
/*分析;Lambda表达式的目的,打印参数传递的字符串
 * 把s传给了System.out对象,调用out中的方法pritnln(),对字符串进行输出
 * 注意:
 * 此时的 System.out对象是存在的,println()方法也是存在的
 * 我们可以使用方法引用来优化Lambda表达式,使用System.out对象直接调用println()方法
 * 格式:		对象::方法
 * 双冒号为 引用运算符,它所在的表达式被称为方法引用
 * */
		printString(System.out::println);
	}

}

😀2、通过对象名 引用成员方法

使用前提:对象名 和 成员方法 已经存在 才可以使用 对象名 来引用 成员方法
注意:如果类中的方法是静态的 就无法使用对象调用 直接用类名 引用 静态成员方法

练习

public class Demo2_ObjectMethodReference {
	public static void printString(Printable p) {
		p.print("java");
	}
	public static void main(String[] args) {
		//调用printString方法,方法的参数Printable是一个函数式接口,所以可以传递Lambda表达式
		printString((s)->{
			//创建MethodFer对象
			MethodFer mf = new MethodFer();
			//使用MethodFer创建的对象 调用 该类中的方法printUpperCase
			mf.printUpperCase(s);	//输出JAVA
		});
		//方法引用(优化)
		MethodFer mf2 = new MethodFer();
		printString(mf2::printUpperCase);	//输出JAVA
		//或者
		printString(new MethodFer()::printUpperCase); //输出JAVA
		/*
		 * printString(MethodFer::printUpperCase);
		 * Cannot make a static reference to the non-static method
		 *  printUpperCase(String) from the type MethodFer
		 */
		
		//通过类 引用 静态成员方法
		printString(MethodFer::printLowerCase); //输出java
	}
}
class MethodFer{
	public void printUpperCase(String str) {
		System.out.println(str.toUpperCase());
	}
	public static void printLowerCase(String str) {
		System.out.println(str.toLowerCase());
	}
}

😀3、通过类名引用静态成员方法

比如:类Math 中的abs方法是静态方法
前提:
类已经存在,静态成员方法也存在, 就可以直接通过类型引用静态成员方法

测试

public class Demo3_StaticMethodReference {

	public static int calcator(int num,Calc c) {
		return c.calcABS(num);
	}
	public static void main(String[] args) {
		int num = calcator(-10,n->Math.abs(n));
		System.out.println(num);
		/*使用方法引用来优化Lambda表达式
		 * Math类是存在的 abs方法也是存在的
		 * */
		int num2 = calcator(-20,Math::abs);
		System.out.println(num2);
	}

}
@FunctionalInterface
interface Calc{
	public abstract int calcABS(int num);
}

😀4、通过super 引用父类的成员方法,通过this 引用本类的成员方法

public class Demo4_Super_this_MethodReference {

	public static void main(String[] args) {
			Man man = new Man();
			man.show1();
			man.show2();
	}

}
//定义一个父类
class Human{
	//定义sayHello方法
	public void Say() {
		System.out.println("Say Hello! I am Father");
	}
}
//定义一个子类
class Man extends Human{
	//重写父类sayHello方法
	public void Say() {
		System.out.println("Say Hi! I am son");
	}
	//定义一个方法 参数传递Greetable接口
	public void method(Greetable g) {
		g.greet();
	}
	//
	public void show1() {
		//调用method方法,方法的参数Greetable是一个函数式接口,所以可以传递Lambda表达式
//		method(()->{
//			//创建父类对象
//			Human h = new Human();
//			//调用父类的sayHello方法
//			h.Say();
//		});
		//因为有子父类关系 所以存在关键字super 代表父类 可以直接使用super调用父类的方法
//		method(()->{
//			super.Say();
//			});
		
/*继续优化  既然 可以直接使用super调用父类的方法
 * 那么就可以使用super引用类的成员方法 
 * 因为super是已经存在的 Say方法是已经存在的 
 * 所以可以直接使用super引用父类的Say方法
*/		method(super::Say);
	}
	public void show2() {
		//调用method方法,方法的参数Greetable是一个函数式接口,所以可以传递Lambda表达式
//		method(()->{
//			//创建本类对象
//			Man man = new Man();
//			//通过本类对象 调用本类的成员方法
//			man.Say();
//		});
		//关键字this 代表本类 可以直接使用this调用本类的方法
//		method(()->{
//			this.Say();
//		});
		//继续优化 使用this 引用本类方法
		method(this::Say);
	}
}
//定义一个见面的函数式接口
@FunctionalInterface
interface Greetable{
	public abstract void greet();
}

😀5、通过构造器 引用成员方法

public class Demo5_ConstructorMethodReference {
	//定义一个方法 参数传递 姓名 和create接口
	public static Person getName(String n,Create c) {
		return c.create(n);
	}
	public static void main(String[] args) {
		//调用getName方法
//		Person name = getName("神厨小福贵",(s)->{
//			return new Person(s);
//		});
//		System.out.println(name);
		
		/*使用方法引用优化Lambda表达式
		 * 构造方法 new Person(String name); 已知
		 * 创建对象 new 已知
		 * 就可以使用Person 引用new 创建对象
		 * */
		Person name = getName("比卡丘",Person::new);
		System.out.println(name);
		
	}
	
}
//定义一个函数式接口
@FunctionalInterface
interface Create{
	//方法返回值为Person 因为要返回创建的对象
	public abstract Person create(String name);
}
//定义一个类
class Person{
	private String name;

	public Person(String name) {
		super();
		this.name = name;
	}

	public Person() {
		super();
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + "]";
	}
}

😀6、数组的构造器引用

public class Demo6_ArrayMethodReference {
	//定义一个返回数组的方法 参数传递 数组的长度 和接口
	public static int[] getArr(int len,CreateArr c) {
		return c.create(len);
	}
	
	public static void main(String[] args) {
		//调用getArr方法 
		int[] arr1 = getArr(10,L->new int[L]);
		System.out.println(Arrays.toString(arr1));
		System.out.println(arr1.length);
		/*使用方法引用优化 Lambda表达式
		 * 已知 数组类型 和数组创建方式
		 * int[]引用new,根据参数传递的长度来创建数组
		 * */
		int[] arr2 = getArr(20,int[]::new);
		System.out.println(Arrays.toString(arr2));
		System.out.println(arr2.length);
	}

}
//定义一个函数式接口
@FunctionalInterface
interface CreateArr{
	//定义一个创建int类型数组的抽象方法 返回值为int[]
	public abstract int[] create(int len);
}

二:链式编程

思想:

是将多个操作(多行代码)通过点号. 链接在一起成为一句代码,使代码可读性好。a(1).b(2).c(3)
下面的函数式编程就是用的这种风格
list.stream().filter(str->str.startsWith("李")).forEach(str->System.out.println(str));

三:常用的函数式接口

定义:有且只有一个抽象方法的接口,称之为函数式接口

当然接口中可以包含其他的方法( 默认,静态,私有)

函数式接口的使用

一般可以作为方法的参数和返回值类型

函数式接口作为 方法的参数 的实例
java.lang.Runnable接口就是一个函数式接口

  • 假设有一个startThread方法使用该接口作为参数,那么就可以使用Lambda表达式进行传参
  • 这种情况其实跟Thread类的构造方法参数为Runnable没有本质区别
public class RunnableDemo {
	//定义一个方法startThread 方法的参数使用 函数式接口Runnable
	public static void startThread(Runnable run) {
		//开启多线程
		new Thread(run) {}.start();
	}
	public static void main(String[] args) {
		
		//调用startThread方法,方法的参数是一个接口,那么我们可以传递这个接口的匿名内部类(或实现类)
		startThread(new Runnable() {
			public void run() {
				System.out.println(Thread.currentThread().getName()+" --> "+"线程开启");
			}
		});
		//调用startThread方法,方法的参数是一个函数式接口,使用Lambda表达式进行传参
		startThread( ()->{
		System.out.println(Thread.currentThread().getName()+" --> "+"线程开启");
		});
		//Lambda表达式优化版本 省略 {} 和 ;
		startThread( ()->System.out.println(Thread.currentThread().getName()+" --> "+"线程开启"));
	}

}

函数式接口作为 返回值类型 的实例

  • 当一个方法的返回值类型是一个函数式接口,那么就可以直接返回一个Lambda表达式
  • 当需要通过一个方法来获取一个java.util.Comparator接口类型的对象作为排序器时,就可以调用该方法获取
public class ComparatorDemo {
	//定义一个方法,方法的返回值类型使用函数式接口Comparator
	public static Comparator<String> getComparator1(){
		//方法的返回值类型是一个接口,那么我们可以返回这个接口的匿名内部类
		return new Comparator<String>() {
			@Override
			public int compare(String o1, String o2) {
				//按照字符串的降序排序
				return o2.length()-o1.length();
			}
		};
	}
	//改进版本		方法的返回值类型是一个函数式接口,所以我们可以返回一个Lambda表达式
	public static Comparator<String> getComparator2(){
		return (String o1,String o2)->{
			//使用字符串的降序排序
			return o2.length()-o1.length();
		};
	}
	//Lambda表达式优化版本
	public static Comparator<String> getComparator3(){
		return (o1, o2)-> o2.length()-o1.length();
	}
	
	
	public static void main(String[] args) {
		//创建一个字符串数组
		String[] arr = {"aaa","ccccc","bbbb"};
		//排序前
		System.out.println("排序前的数组:");
		System.out.println(Arrays.toString(arr));
		//进行升序排序
		Arrays.sort(arr);
		System.out.println("默认升序排序后的数组:");
		System.out.println(Arrays.toString(arr));
		//进行降序排序
		Arrays.sort(arr,getComparator3());
		System.out.println("降序排序后的数组:");
		System.out.println(Arrays.toString(arr));
	}

}

运行结果
在这里插入图片描述

这个包就包含了所有的函数式接口
在这里插入图片描述
该包下有许多接口,其中 主要的是这四个接口
在这里插入图片描述

1、java.util.function.Function<T , R>接口

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

根据一个类型的数据得到另一个类型的数据,前者 为前置条件 后者 为后置条件
Function接口中最主要的抽象方法为:
R apply(T t),根据类型T的参数获取类型R的结果,andThen():用来进行组合操作
在这里插入图片描述

题目:将String 转换为Integer

方法:

	/*方法参数传递一个字符串类型的整数,和一个Function接口,泛型使用<String,Integer>
	 * 使用Function接口中的方法apply,把字符串类型的整数,转换为Integer类型的整数
	 * */
	public static void method(String str,Function<String,Integer> fun) {
		int num = fun.apply(str);
		num+=100;
		System.out.println(num+0);
	}

main:

// 输出 234
		method("123",new Function<String,Integer>(){
			@Override
			public Integer apply(String t) {
				return Integer.parseInt(t);
			}
		});
//使用Lambda表达式简化
		method("234",str-> Integer.parseInt(str));

题目:把String类型的“123” 转换为Integer类型的整数,再加10 ,再转为String 使用 andThen

方法:

public static void method(String str,Function<String,Integer> fun1,Function<Integer,String> fun2) {
		/*	分两步操作	
		int num = fun1.apply(str);
		str = fun2.apply(num);
		System.out.println(str);
		*/
		//使用andThen合成一步
		String app = fun1.andThen(fun2).apply(str);
		System.out.println(app+0);
	}

main:

method("123",str->Integer.parseInt(str)+10,num->num.toString());

2、java.util.function.Supplier 接口

仅包含一个无参方法
在这里插入图片描述
在这里插入图片描述

  • T get() 用来获取一个泛型参数指定类型的对象数据
  • Supplier 接口被称之为生产型接口(供应商接口)
  • 指定接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据

练习

public class SupplierDemo1 {
	//定义一个方法,方法的参数传递Supplier<T>接口,泛型执行String,get方法就会返回一个String
	public static String getString(Supplier<String> sup) {
		return sup.get();
	}
	public static void main(String[] args) {
		System.out.println(getString( ()->{ return "光头强";}));
		System.out.println(getString( ()->  "天才威"));
	}

}

题目:求数组元素的最大值:
使用Supplier接口作为方法参数类型,通过Lambda表达式求出int数组的最大值

public class SupplierDemo_GetArrMax {
	public static int getMax(Supplier<Integer> sup) {
		return sup.get();
	}
	public static void main(String[] args) {
		//定义一个整型数组
		int[] arr = {1,8,5,9,2,55,11,77,66};
		//调用getMax方法,使用Supplier接口作为方法参数类型
		//通过Lambda表达式求出int数组的最大值
		int maxNum = getMax( ()->{ 
			//定义一个变量存放数组中第一个数
			int num = arr[0];
			//循环查找
			for (int i : arr) {
				if(i>num)
					num = i;
			}
			return num;
		});
		System.out.println("数组中最大值为:"+maxNum);
	}

}

3、java.util.function.Predicate 接口

在这里插入图片描述

作用:对某种数据类型的数据进行判断,结果返回一个boolean值

Predicate接口中包含一个抽象方法:
在这里插入图片描述

boolean test(T t):用来对指定数据类型数据进行判断的方法

  • 结果:
    • 符合条件:返回true
    • 不符合条件:返回false

练习

public class PredicateDemo {
	/*
	 * 定义一个方法
	 * 参数传递一个String类型的字符串
	 * 传递一个Predicate接口,泛型使用String
	 * 使用Predicate中的方法test对字符串进行判断,并把判断结果返回
	 * */
	public static boolean method(String str,Predicate<String> pre) {
		return pre.test(str);
		
	}
	public static void main(String[] args) {
		//如果字符串长度大于五则 返回true
		System.out.println(method("absafjsdf",(str)->{ return str.length()>5;}));
		System.out.println(method("abc",str-> str.length()>5 ));
	}

}

其他方法测试

public class PredicateDemo {
	//and实例	条件必须都满足 相当于&&
	public static boolean checkingAnd(String str,Predicate<String> p1,Predicate<String> p2) {
//		return p1.test(str) && p2.test(str);
		return p1.and(p2).test(str);
	}
	//or实例  条件满足一个即可 相当于 ||
	public static boolean checkingOr(String str,Predicate<String> p1,Predicate<String> p2) {
//		return p1.test(str) || p2.test(str);
		return p1.or(p2).test(str);
	}
	//negate表示取反 即为!
	public static boolean checkingNegate(String str,Predicate<String> p1) {
//		return !p1.test(str);
		return p1.negate().test(str);
	}
	public static void main(String[] args) {
		//And实例 true
		System.out.println(checkingAnd("ABFDFD",str->str.length()>5 , str->str.contains("A")));
		//Or实例 true
		System.out.println(checkingOr("ABFDFD",str->str.length()>10 , str->str.contains("A")));
		//Negate实例 false
		System.out.println(checkingNegate("adadad",str->str.length()>5));
	}

}

4、java.util.function.Consumer 接口

在这里插入图片描述

正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定

  • Consumer接口中包含抽象方法 void accept( T t),意为消费一个指定泛型的数据
  • Consumer接口是一个消费型接口,泛型指定什么类型,就可以使用accpet方法消费什么类型的数据
  • 至于具体如何消费( 使用 ),需要我们自定义( 输出,计算。。。)
    在这里插入图片描述

练习

public class ConsumerDemo {
	/*定义一个方法	方法的参数传递一个字符串的姓名
	 * 方法的参数传递Consumer接口,泛型使用String
	 * 可以使用Consumer接口消费字符串的姓名
	 * */
	public static void consumerName(String name,Consumer<String> con) {
		 	con.accept(name);
	}
	public static void main(String[] args) {
		//使用匿名内部类
		consumerName("光头强",new Consumer<String>() {
			public void accept(String t) {
				System.out.println(t);
			}
		});
		//因为此接口为 函数式接口 所以可以使用Lambda表达式
		// (String t )->{ System.out.println(t); }
		consumerName("天才威", t->System.out.println(t));
		
		//实现字符串反转输出
		consumerName("翠花",t-> System.out.println(new StringBuffer(t).reverse()) );
	}
}

Consumer接口的默认方法addThen
作用:需要两个Consumer接口,可以把两个Consumer接口组合到一起,再对数据进行消费

例如:
Consumer con1
Consumer con2
String s = “Hello”;
con1.accpet(s);
con2.accpet(s);

  • 改善:连接两个Consumer接口,再进行消费
  • con1.addThen(con2).accpet(s); 谁写前边谁先消费
public class ConsumerDemo {
	//定义一个方法,方法的参数传递一个字符串和两个Consumer接口,接口泛型使用字符串类型
	public static void method(String str,Consumer<String> con1,Consumer<String> con2) {
		con1.accept(str);
		con2.accept(str);
	}
	public static void method2(String str,Consumer<String> con1,Consumer<String> con2) {
		con1.andThen(con2).accept(str);
	}
	public static void main(String[] args) {
		//调用method方法,传递一个字符串,两个Lambda表达式
		method("I am CSNZ",t->System.out.println(t.toUpperCase()),t->System.out.println(t.toLowerCase()));
		method2("I am CSNZ",t->System.out.println(t.toUpperCase()),t->System.out.println(t.toLowerCase()));
	}

}

题目:字符串数组中存有多条信息,按照格式:“姓名:xx。性别:xx。”打印
使用两个Consumer接口 最后andThen

	public static void print(String[] a,Consumer<String> c1,Consumer<String> c2) {
		for (String str : a) {
			c1.andThen(c2).accept(str);
		}
	}
	public static void main(String[] args) {
		//定义一个字符串数组
		String[] arr = {"迪丽热巴,女","古力娜扎,女","马儿扎哈,男"};
		print(arr,(str)->{
			System.out.print("姓名:"+str.split(",")[0]+"。");
		},(str)->{
			System.out.print("性别:"+str.split(",")[1]+"。\n");
		});
	}	
}

执行结果:
在这里插入图片描述

四:Stream流式计算

在这里插入图片描述

java.util.stream.Stream 是java 1.8 新加入的最常用接口。(这并不是一个函数式接口,里面不止一个抽象方法)

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

获取一个流的方式:

所有的Collection集合都可以通过stream的默认方法获取流
在这里插入图片描述

Stream接口的静态方法of可以获取可变长参数(底层即数组)对应的流

在这里插入图片描述
参数是一个可变参数,那么我们就可以传递一个数组

练习

public class StreamDemo {
	public static void main(String[] args) {
		//把集合转换为stream
		List<String> arrayList = new ArrayList<String>();
		Stream<String> stream1 = arrayList.stream();
		
		Set<String> hashset = new HashSet<>();
		Stream<String> stream2 = hashset.stream();
		
		
		//如果是Map集合的话(双列集合)
		Map<String,String> hashMap = new HashMap<String,String>();
		
		//获取键,存储到一个set集合中,再转换成流
		Set<String> keySet = hashMap.keySet();
		Stream<String> stream3 = keySet.stream();
		//获取值,存储到一个Collection集合中,再转换成流
		Collection<String> values = hashMap.values();
		Stream<String> stream4 = values.stream();
		//获取键值对(键与值的映射关系 entrySet)
		Set<Entry<String, String>> entrySet = hashMap.entrySet();
		Stream<Entry<String, String>> stream5 = entrySet.stream();
		
		
		//把数组转换为Stream流
		Stream<Integer> stream6 = Stream.of(1,2,3,4,5);
		//可变长参数可传递数组
		int[] arr1 = {666,7,888};
		Stream<int[]> stream7 = Stream.of(arr1);
		Integer[] arr2 = {666,7,888};
		Stream<Integer> stream8 = Stream.of(arr2);
		String[] arr3 = {"a","bb","ccc"};
		Stream<String> stream9 = Stream.of(arr3);
		
	}
}

Stream流中常用方法 forEach

  • void forEach( Consumer <? super T> action);
  • 该方法接收一个Consumer接口函数,会将每一个流元素交给该函数处理
  • Consumer接口是一个消费型的函数式接口,可以传递Lambda表达式进行消费
  • Consumer中的抽象方法
    • void accept(T t);
  • forEach:即遍历流中的数据 是一个终结方法 遍历之后就不能调用stream流中的其他方法
public static void method1() {
		//创建一个Stream流
		Stream<Integer> stream1 = Stream.of(1,6,4,2,8);
		//使用Stream流中的方法forEach对流中的数据进行遍历
		stream1.forEach( str->System.out.println(str));
	}

Stream流中的常用方法filter:用于对Stream流中的数据进行过滤

  • Stream filter( Predicate<? super T> pre);
  • filter方法的参数是一个函数式接口,所以可以传递Lambda表达式,对数据进行过滤
  • Predicate中的抽象方法
    • boolean test(T t);
public static void method2() {
		//创建一个流
		Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6);
		//对流中的数据进行过滤 只要偶数
		Stream<Integer> stream3 = stream2.filter(num->num%2==0);
		//对新的流进行遍历
		stream3.forEach(num->System.out.println(num));
	}

如果需要将流中数据映射到另一个流中,可以使用map方法

  • Stream map(Function<? super T, ? extends R> mapper);
  • 该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的数据
  • Function中的抽象方法
    • R apply(T t);
public static void method3() {
		//创建一个流
		Stream<String> stream1 = Stream.of("1","2","3","4","5");
		//将字符串转换为整数类型
		Stream<Integer> stream2 = stream1.map(str->Integer.parseInt(str));
		stream2.forEach(num->System.out.println(num));
	}

Stream流中的常用方法:count:用于统计 流中元素个数

  • 是一个终结方法,返回值是一个long类型的整数,所以在这之后无法调用其他的方法
public static void method4() {
		//创建一个流
		Stream<String> stream1 = Stream.of("1","2","3","4","5");
		long count = stream1.count();
		System.out.println(count);
	}

Stream流中的常用方法:limit:用于截取流中的元素,只取前n个

  • Stream limit(long maxSize):
    • 参数是一个long型,如果集合当前长度大于参数则进行截取,否则不进行操作
  • limit方法是一个延迟方法,对流进行截取,返回一个新的流,可以继续调用流中的其他方法
public static void method5() {
		//创建一个流
		Stream<String> stream1 = Stream.of("火花","水蓝篮","喵喵","少林呱呱","邪恶玄武");
		//对流中的元素进行截取
		Stream<String> stream2 = stream1.limit(3);
		//对截取的流进行遍历
		stream2.forEach(str->System.out.println(str));
	}

Stream流中的常用方法:skip:用于跳过元素

  • Stream skip(long n);
  • 如果流的当前长度大于n,则跳过前n个,否则会得到一个长度为0的流
public static void method6() {
		//创建一个流
		Stream<String> stream1 = Stream.of("火花","水蓝篮","喵喵","少林呱呱","邪恶玄武");
		//对流进行跳过截取
		Stream<String> stream2 = stream1.skip(3);
		//对截取的流进行遍历
		stream2.forEach(str->System.out.println(str));
	}

Stream流中的常用方法:concat:用于把流组合到一起

  • static Stream concat(Stream <? extends T> a , Stream<? extends T> b)
public static void method7() {
		//创建一个流
		Stream<String> stream1 = Stream.of("火花","水蓝篮","喵喵","少林呱呱","邪恶玄武");
		//创建另一个流
		Stream<String> stream2 = Stream.of("1","2","3","4","5");
		//将两个流进行合并
		Stream<String> stream3 = Stream.concat(stream1, stream2);
		//遍历合并的流
		stream3.forEach(str->System.out.println(str));
	}

执行结果:
在这里插入图片描述
题目:使用stream流对数组中的元素进行筛选遍历

public class Stream_List_demo {

	public static void main(String[] args) {
		//新建一个存储元素的集合
		ArrayList<String> list = new ArrayList<>();
		list.add("李白");
		list.add("李黑");
		list.add("白黑");
		list.add("黑白");
		list.add("李黑白");
		
		/*普通方法筛选和遍历
		ArrayList<String> list2 = new ArrayList<>();
		for(String s:list) {
			if(s.startsWith("李") && s.length()==2) {
				list2.add(s);
			}
		}
		for (String str : list2) {
			System.out.println(str);
		}
		*/
		
		//使用stream流筛选遍历 结合函数式编程
		list.stream().filter(str->str.startsWith("李"))
		.filter(str->str.length()==2)
		.forEach(str->System.out.println(str));
	}
}

Stream流的特点:

  • 它属于管道流,只能被消费(使用)一次
  • 第一个Stream流调用完毕后,数据就会传到下一个Stream上
  • 此时第一个流 就会自动关闭 无法再进行使用了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值