Java基础30(Java 8 特性 Java8中Interface接口 Lambda 表达式 Stream流)

目录

一、 Java8中Interface接口

 二、Lambda 表达式

1. lambda的精简写法

2. 函数式接口 Functional Interface

3. 内置函数式接口(Built-in Functional Interfaces)

3.1 Supplier 供给型接口

3.2 Consumer 消费型接口

3.3 Function 函数型接口,r>

3.4 Predicate 断言型接口 ,r>

三、Stream流

1. 创建Stream

2. foreach方法

2. Filter 过滤

3. limit(long )--获取流中的前n个元素

4. skip()--跳过前几个元素 

5. Map 映射

6. Sorted 排序

7. Match 匹配

8. distinct去掉重复的元素9

9. Collectors

Collectors.mapping()将Stream中的元素,映射后,收集至新集合

Collectors.groupingBy() 分组

10. Parallel Streams 并行流

函数式接口总结


一、Java8中Interface接口

interface接口 的设计目的是面向接口编程,提高扩展性。
●Java8中,接口中除了抽象方法外,还可以定义default默认方法和static静态方法。
○default修饰的默认方法,属于实例方法,可以被实现类调用或重写。

  • 调用:实现类必须implements接口,才能调用该接口的default默认方法。
  • 重写:实现类implements不同接口时,接口中存在相同签名的方法(名称、参数、类型完全一致),则实现类必须重写该方法,明确方法定义;

○static修饰的静态方法,属于类的静态方法。但它不能被子类继承,只能用interface接口名称调用。

 二、Lambda 表达式

  • Lambda 表达式本质是一个匿名函数,用于把函数作为参数,传入方法中,实现函数式编程风格。
  • 使用Lambda 表达式可以使代码变的更加简洁紧凑。

语法格式
 

(parameters)-> expression 或 (parameters)->{ statements;}

接口名 对象名=(参数类型 参数名称)->{方法体}
(参数类型,参数名称): 抽象方法的参数,形参
->固定写法
{}存放方法的内容
public static void main(String[] args) {
		new Thread(new Runnable() {
			// 1.定义了一个没有名字的内部类
			// 2.实现了Runnable接口
			// 3.创建Runnable实现类对象
			@Override
			public void run() {
				System.out.println("子线程1执行任务");
			}
		}).start();

		new Thread(() -> System.out.println("子线程2执行任务")).start();

		System.out.println("主线程执行任务");
	}

运行结果:
子线程1执行任务
主线程执行任务
子线程2执行任务

创建函数式接口类型的对象
函数式接口:接口中只有一个抽象方法(static default,抽象方法只能有1个)

//创建函数式接口类型的对象
//函数式接口:接口中只有一个抽象方法(static default,抽象方法只能有1个)

//接口名 对象名=(参数类型 参数名称)->{方法体}
//(参数类型,参数名称): 抽象方法的参数,形参
//->固定写法
//{}存放方法的内容

//lambda的精简写法
//a.参数的类型省略
//b.()可以省略,参数个数只有1个的时候可以省略
//c.{ return ;}可以省略,只有一条语句的时候才能省略
public class Demo02 {
	public static void main(String[] args) {
		goSWimining(new Swimable() {

			@Override
			public void swimming() {
				System.out.println("zkt在游泳");
			}
		});

		//接口名对象名=(参数类型参数名称)->{方法体}
		goSWimining(() -> {
			System.out.println("zkt1在游泳");
		});
		goSWimining(() -> System.out.println("zkt2在游泳"));
	}

	public static void goSWimining(Swimable s) {
		s.swimming();
	}
}

interface Swimable {
	void swimming();
}

1. lambda的精简写法

  • 参数的类型省略
  • ()可以省略,参数个数只有1个的时候可以省略
  • { return ;}可以省略,只有一条语句的时候才能省略
public static void main(String[] args) {
		List<Integer> list = new ArrayList<Integer>(Arrays.asList(3,2,1,5,6,7));
		
		//写法1:匿名内部类写Compartor实现类对象
//		Collections.sort(list,new Comparator<Integer>() {
//
//			@Override
//			public int compare(Integer o1, Integer o2) {
//				// TODO Auto-generated method stub
//				return o2-o1;
//			}
//		});
		//写法2:1ambda表达式写法
		Collections.sort(list,(Integer o1,Integer o2)->{return o2-o1;});
		
		//写法3:省略参数类型
		Collections.sort(list,( o1, o2)->{return o2-o1;});
		
		//写法4:省略{return ;}
		Collections.sort(list,( o1, o2)->o2-o1);
		
		System.out.println(list);
	}
public class Demo04 {
	public static void main(String[] args) {
		List<Person> persons = new ArrayList<Person>();
		persons.add(new Person("zkt1", 21,177));
		persons.add(new Person("zkt2", 17,180));
		persons.add(new Person("zkt3", 24,187));
		
		Collections.sort(persons,(p1,p2)->{return p1.getAge()-p2.getAge();});
		
		persons.forEach((t)->{System.out.println(t);});
	}
}

class Person {
	private String name;
	private int age;
	private int height;

	public Person(String name, int age, int height) {
		super();
		this.name = name;
		this.age = age;
		this.height = height;
	}

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


	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 getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}

}


2. 函数式接口 Functional Interface

只有一个抽象方法的接口(可以定义多个非抽象方法)。可以使用@FunctionalInterface接口定义,强化语义规范。
函数式接口,也被称为SAM 接口(Single Abstract Method Interfaces)

作用
基于函数式接口,可以使用Lambda表达式进行实现,实现函数式编程。

//lambda表达式使用的前提:
//1.方法的参数或者变量的类型是接口
//2.这个接口中只能有一个抽象方法
public class Demo05 {
	public static void main(String[] args) {
		test(new Flyable() {

			@Override
			public void fly() {
				System.out.println("我能飞");
			}
		});

		test(() -> {
			System.out.println("我能飞");
		});
	}

	public static void test(Flyable fly) {
		fly.fly();
	}
}
@FunctionalInterface //函数式接口注解,表示此接口只有一个
interface Flyable {
	public abstract void fly();

}
public class Demo01 {
	public static void main(String[] args) {
		//调用函数式接口中的方法
		method((arr) -> {
			int sum = 0;
			for (int i : arr) {
				sum = sum + i;
			}
			return sum;
		});
	}
    //使用自定义的函数式接口作为方法的参数
	public static void method(Opertor op) {
		int[] arr = { 1, 2, 3, 4 };
		int sum = op.getSum(arr);
		System.out.println(sum);
	}
}

@FunctionalInterface
interface Opertor {
	int getSum(int[] arr);
}

3. 内置函数式接口(Built-in Functional Interfaces)

在 Java 8 中专门有一个包放函数式接口java.util.function,该包下的所有接口都有 @FunctionalInterface 注解,提供函数式编程方式。

3.1 Supplier<T> 供给型接口

抽象方法描述
T get()返回一个自定义数据( 无参数,有返回值)
public class Demo02Supplier {
	public static void main(String[] args) {
		// Supplier --- 供给型接口
		// T get();--方法没有参数,有返回值,需要对外提供一个符合泛型类型的对象数据
		System.out.println("main中的方法");
		printMax(()->{
			System.out.println("Supplier对象的get方法");
			int[] arr = {1,3,5,10,4};
			Arrays.sort(arr);
			return arr[arr.length-1];
		});
	}

	//输出数组中最大的元素
	public static void printMax(Supplier<Integer> sup) {
		System.out.println("printMax方法");
		int max = sup.get();
		System.out.println(max);
	}

}

运行结果:
main中的方法
printMax方法
Supplier对象的get方法
10
public class Demo03Supplier2 {
	public static void main(String[] args) {
		// Supplier --- 供给型接口
		// T get();

		// 1-100之间的随机数
		//getRandNum(() -> (int) (Math.random() * 100 + 1));

		// 20-100随机的数--偶数 
		Supplier<Integer> sup = () -> {
			while(true) {
				int random = (int) (Math.random() * 80 + 20);
				if((random & 1) == 0) {
					return random;
				}
			}
		};
		getRandNum(sup);
		
	}

	public static void getRandNum(Supplier<Integer> sup) {
		Integer integer = sup.get();
		System.out.println(integer);
	}

}

3.2 Consumer<T> 消费型接口

抽象方法描述
void accept(T t)接收一个参数进行消费,无返回结果 (因为没有返回值,接口里面执行内容和调用方没什么关联 – 解耦

public class Demo04ConSumer {
	public static void main(String[] args) {
		// ConSumer消费型接口 void accept(T t);
		// 方法有参数,没有返回值,消费一个数据,数据类型由泛型决定
		
		//字符串转大写
		Consumer<String> con1 = s -> System.out.println(s.toUpperCase());
		//printUpper(con1, "HelloWorld");
		
		//字符串转小写
		Consumer<String> con2 = s -> System.out.println(s.toLowerCase());
		//printLower(con2, "HelloWorld");

		printUpeerAndLower(con1,con2,"hxjxky");
	}

	public static void printUpper(Consumer<String> con, String str) {
		con.accept(str);
	}

	public static void printLower(Consumer<String> con, String str) {
		con.accept(str);
	}
	
	public static void printUpeerAndLower(Consumer<String> con1,Consumer<String> con2, String str) {
//		con1.accept(str);
//		con2.accept(str);
		
		//使用默认方法andThen()
		//在消费一个数据的时候,可以先做一个操作,然后再做一个操作,实现操作组合
		con1.andThen(con2).accept(str);
	}

}
运行结果:
HXJXKY
hxjxky

3.3 Function<T,R> 函数型接口

Function 接口接受一个参数并生成结果。默认方法可用于将多个函数链接在一起(compose, andThen)。
抽象方法描述
R apply(T t)传入一个参数,返回需要的结果
public class Demo05Function {
//	    interface Function<T, R> ---转换接口
//	    R apply(T t);
	public static void main(String[] args) {
		//将字符串数字转成数字
		//Function<String, Integer> fun =(str)->{return Integer.parseInt(str);};
		
		//简写方式
		Function<String, Integer> fun =str-> Integer.parseInt(str);
		method(fun,"12345");
		
		//打印字符串的长度
		method(str-> str.length(), "aabmdijej");
	}
	
	public static void method(Function<String,Integer> f,String str) {
		Integer num = f.apply(str);
		System.out.println(num);
	}
}
运行结果:
12345
9
public class Demo06Function2 {
	public static void main(String[] args) {
       method(str->str.length(),
    		  num->new double[num], "abdf");
	}

	//将一个字符串转成对应的长度的double类型的数组
	// string-->Integer
	// Integer-->double[]
	public static void method(Function<String, Integer> f1, Function<Integer, double[]> f2, String str) {
		Integer num = f1.apply(str);
		double[] d = f2.apply(num);
		System.out.println(Arrays.toString(d));
	}

}
运行结果:
[0.0, 0.0, 0.0, 0.0]

3.4 Predicate<T,R> 断言型接口 

Predicate接口是只有一个参数的返回布尔类型值的 断言型 接口。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与and,或or,非negate)
抽象方法描述
boolean test(T t)传入一个参数,返回布尔值(满足:true,不满足:false)
public class Demo07Predicate {
	// Predicate boolean test(T t)--传入一个参数,返回值为布尔类型的
	// 根据传入的参数,进行某些判断,结果boolean
	// 断言型接口
	public static void main(String[] args) {
		//判断某个数字是否是偶数
		//boolean b=method((num)->{return (num&1)==0;},102);
		Predicate<Integer> p1=num->(num&1)==0;
		boolean b=method(p1,102);
		System.out.println("102是否是偶数:"+b);
		
		//判断某个数字是否大于100
		Predicate<Integer> p2=num->num>=100;
		boolean b1 =method(p2, 22);
		System.out.println("22是否是大于100:"+b1);
		
		boolean b2 =method(p1,p2,5);
		System.out.println(b2);
	
	}
	
	public static boolean method(Predicate<Integer> pre,Integer num) {
		boolean b=pre.test(num);
		return b;
	}
	
	
	public static boolean method(Predicate<Integer> p1,Predicate<Integer> p2,Integer num) {
		//与运算
		boolean b=p1.and(p2).test(num);
		//或运算
		boolean b1=p1.or(p2).test(num);
		//非
		boolean b2=p1.negate().test(num); 
		return b2;
	}
}

运行结果:
102是否是偶数:true
22是否是大于100:false
true

三、Stream流

  • java.util.Stream 表示能应用在一组元素上一次执行的操作序列。
  • Stream操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,可以连续完成多个操作。
public class Demo01 {
	public static void main(String[] args) {
		List<String>  list = new ArrayList<String>();
		Collections.addAll(list,"张三","李四","王五","张kt");
		
		//1.拿到所有姓张的元素
		ArrayList<String> listZhangArrayList = new ArrayList<String>();
		for (String string : list) {
			if(string.startsWith("张")) {
				listZhangArrayList.add(string);
			}
		}
		//2.拿到长度为3的元素
		ArrayList<String> threeArrayList = new ArrayList<String>();
        for (String string : listZhangArrayList) {
			if(string.length() ==3)
				threeArrayList.add(string);
		}
		//3.打印保存
        
        for (String string : threeArrayList) {
			System.out.println(string);
		}
        System.out.println("================");
        
        list.stream().
        filter(str->str.startsWith("张"))
        .filter(str->str.length()==3).
        forEach(str->System.out.println(str));
	}

}

1. 创建Stream

Stream 的创建需要指定一个数据源。

//Stream流的创建方法
public class Demo02 {
//	1.Collection集合提供方法 default Stream<E> steam()
//	2.Stream接口提供of
	public static void main(String[] args) {
//		1.Collection集合提供方法 default Stream<E> steam()
		List<String> list = new ArrayList<String>();
		Stream<String> stream1 = list.stream();
		System.out.println(stream1);

		Set<String> set = new HashSet<String>();
		stream1 = set.stream();
		System.out.println(stream1);

		Map<Integer, String> map = new HashMap<Integer, String>();
		Stream<Integer> strem2 = map.keySet().stream();
		Stream<String> strem3 = map.values().stream();
		Stream<Map.Entry<Integer, String>> strem4 = map.entrySet().stream();
	
	   //方式2:
		Stream<String> strem5 =Stream.of("aa","bb","cc");
	
		String[] strs = {"aa","bb","cc"};
		Stream<String> strem6 =Stream.of(strs);
		
		int[] ints= {1,2,3,4,5};
		Stream<int[]> strem7 =Stream.of(ints);
	}

}

2. foreach方法

List<String> list = new ArrayList<String>();
		Collections.addAll(list, "z张三", "l李四", "w王五", "z张kt");

		// 1.foreach方法--
		 list.stream().forEach(str-> System.out.println(str));
		 System.out.println(list.stream().count());
运行结果:
z张三
l李四
w王五
z张kt
4

2. Filter 过滤

过滤通过一个predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作。所以过滤后的结果,可以继续进行其它Stream操作(例如forEach,forEach需要一个函数来对过滤后的元素依次执行。forEach是一个最终操作)。

	List<String> list = new ArrayList<String>();
		Collections.addAll(list, "张三", "李四", "王五", "z张柯特");
		// 3.filter()
		 list.stream().filter((str)->str.length()==2).forEach(System.out::println);
运行结果:
张三
李四
王五

3. limit(long )--获取流中的前n个元素

List<String> list = new ArrayList<String>();
		Collections.addAll(list, "张三", "李四", "王五", "z张柯特");
		
		// 4.Stream limit(long )--获取流中的前n个元素
		 list.stream().limit(3).forEach(System.out::println);
运行结果:
张三
李四
王五

4. skip()--跳过前几个元素 

List<String> list = new ArrayList<String>();
		Collections.addAll(list, "张三", "李四", "王五", "z张柯特");
		// 5.skip()--跳过前几个元素
		 list.stream().skip(2).forEach(System.out::print);
运行结果:
王五z张柯特

5. Map 映射

映射是一个中间操作, 会将元素根据指定的 Function 接口来依次将元素转成另外的对象。

List<String> list = new ArrayList<String>();
		Collections.addAll(list, "张三", "李四", "王五", "z张柯特");
		// 6.map()--可以将一种流转成另一种流
		 list.stream().map((str)->{return
		 str.length();}).forEach(System.out::println);
运行结果:
2
2
2
4

6. Sorted 排序

排序是一个 中间操作,返回的是排序好后的 Stream。(不影响原数据)

List<String> list = new ArrayList<String>();
		Collections.addAll(list, "z张三", "l李四", "w王五", "z张柯特");

		// 7.sorted() sorted(Compartor)
		 list.stream().sorted((s1,s2)->{return
		 s2.length()-s1.length();}).forEach(System.out::println);
运行结果:
z张柯特
z张三
l李四
w王五

7. Match 匹配

Stream提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。所有的匹配操作都是 最终操作 ,并返回一个 boolean 类型的值。

List<String> list = new ArrayList<String>();
		Collections.addAll(list, "z张三", "l李四", "w王五", "z张柯特");


		// 8.allMatch()--判断所有的元素是否满足某个条件
		// anyMatch() noneMatch
		boolean b=list.stream().allMatch(str->str.length()==3);
		System.out.println(b);
	
		boolean b1=list.stream().anyMatch(str->str.length()==3);
		System.out.println(b1);
		
		boolean b3 = list.stream().noneMatch(str -> str.length() == 4);
		System.out.println(b3);
运行结果:
false
true
false

8. distinct去掉重复的元素9

public class Demo03 {
	public static void main(String[] args) {
		ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList("aa","bb","cc"));
		
		arrayList.stream().distinct().forEach(System.out::println);
		ArrayList<Person> persons = new ArrayList<Person>();
		persons.add(new Person("zkt1"));
		persons.add(new Person("zkt2"));
		persons.add(new Person("zkt1"));
		persons.add(new Person("zkt2"));
		
		persons.stream().distinct().forEach(System.out::println);
	}
}
class Person{
	private String nameString;

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

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

	@Override
	public String toString() {
		return "Person [nameString=" + nameString + "]";
	}
	
	
}
运行结果:
aa
bb
cc
Person [nameString=zkt1]
Person [nameString=zkt2]

9. Collectors

public static void main(String[] args) {
		// ● Collectors.toList()
		// ● Collectors.toSet()
		// ● Collectors.toMap()
		// Collectors.toCollection()
		List<String> langList = Arrays.asList("abc", "debft", "gkh", "abc");
		LinkedList<String> newList2 = langList.stream().filter((s) -> s.contains("b"))
				.collect(Collectors.toCollection(LinkedList::new));
		List<String> newList1 = langList.stream().filter((s) -> s.contains("b")).collect(Collectors.toList());
		Set<String> newset1 = langList.stream().filter((s) -> s.contains("b")).collect(Collectors.toSet());
		Map<String, Integer> newmap1 = langList.stream().filter(s -> s.contains("b")).distinct()
				.collect(Collectors.toMap(s -> s, s -> s.length()));

		System.out.println(newList2);
		System.out.println(newset1);
		System.out.println(newmap1);
	}
运行结果:
[abc, debft, abc]
[abc, debft]
{abc=3, debft=5}

Collectors.mapping()将Stream中的元素,映射后,收集至新集合

public static void main(String[] args) {
	
			List<String> numberStrings = Arrays.asList("4344", "6641", "3432", "6432", "6423", "9423");

			//Collectors.mapping()将Stream中的元素,映射后,收集至新集合
			//过滤掉不包含字符3的元素,并将其转成Integer类型的集合
			List<Integer> intList = numberStrings.stream().filter(s -> s.contains("3"))
					.collect(Collectors.mapping(s -> Integer.parseInt(s), Collectors.toList()));
			for (Integer integer : intList) {
				System.out.println(integer);
			}

		}

Collectors.groupingBy() 分组

public static void main(String[] args) {
		// Collectors.groupingBy() 分组

		List<String> langList = Arrays.asList("abc", "de", "gkhf", "abc");
		// 按照首字符分组
		Map<Character, List<String>> map = langList.stream()
				.collect(Collectors.groupingBy((s) -> s.charAt(0), Collectors.toList()));
		System.out.println(map);

		// 按照长度分组
		Map<Integer, List<String>> map1 = langList.stream()
				.collect(Collectors.groupingBy((s) -> s.length(), Collectors.toList()));
		System.out.println(map1);

	}
运行结果:
{a=[abc, abc], d=[de], g=[gkhf]}
{2=[de], 3=[abc, abc], 4=[gkhf]}

10. Parallel Streams 并行流

Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。

public static void main(String[] args) {
		ArrayList<Integer> arrayList = new ArrayList<Integer>();

		// 获取并行流的方法1:.parallelStream()
		Stream<Integer> stream1 = arrayList.parallelStream();
		// 获取并行流的方法2:stream().parallel()
		Stream<Integer> stream2 = arrayList.stream().parallel();

		//检查查并行流
		testParaller();
	}

	// 并行
	private static void testParaller() {
		long number=Stream.of(9, 3, 4, 6, 1).parallel().filter(num -> {
			System.out.println(Thread.currentThread().getName() +"@"+ num);
			return true;
		}).count();
		System.out.println(number);
	}

函数式接口总结

  • Predicate、Function、Consumer、Comparator
  • 通过链式编程,使得它可以方便地对数据进行链式处理。
  • 方法参数都是函数式接口类型。
  • 一个 Stream 只能操作一次,操作完就关闭了,继续使用这个 Stream 会报错。
  • Stream 不保存数据,不改变数据源。

  • 23
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冯诺依曼转世

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值