便捷编程——java8特性

java8特性

java8是一个分界线

接口特性

一、概述
接口中可以定义抽象方法和非抽象方法,弱化了抽象类
非抽象方法可以拥有方法体,不过需要加上default、static关键字

二、default关键字
接口,接口
1.接口中不止是抽象方法,可以有某些实现方法,使用default修饰,并且该实现方法不要求必须重写
2.如果多个接口声明了同样的默认方法(使用default修饰的方法),那么在实现类中必须重写该方法(普通接口:多个接口拥有相同的方法声明,必须重写)
3.如果多个接口定义了不同的默认方法,那么在实现类中必须重写该方法,可指定其中一个具体实现作为重写结果,格式:接口名.super.方法(super表示对应接口的实现类对象)

类,接口:父类优先
4.实现类继承了一个父类,一个接口,且有相同的方法名,接口中是默认方法。默认使用父类的方法实现。
5.实现类继承了一个抽象父类,一个接口,且有相同的方法名,接口中是默认方法,抽象父类中是方法声明。默认重写父类中的方法。

三、static关键字
1、接口中可以创建静态方法,调用时直接使用:接口名.静态方法。不能用实现类对象调用

interface IntTest{
	public static void test() {
		System.out.println("接口中可以定义静态方法");
	}
}

2、static与abstract关键字共存,没有意义。
3、static只能被public、protected关键字修饰

Lambda表达式

一、简述
1、本质:表达一个对象(指定的接口的实现类对象)
2、前提:这种对象所属的类,必须是一个接口;函数式接口(接口中只能有一个抽象方法)
3、好处:简洁、突出重点

二、语法

(参数列表)—>{方法体}
1、参数列表:是指那个抽象方法的参数列表
	注意
		只需要保证参数个数即可,不需要管参数类型和参数名称
2、箭头:分隔符,没实际意义
3、方法体:是指那个抽象方法重写的方法体
public class demo_Lambda {
	
	public static void main(String[] args) {
		TestLambda tl = (x,y,z)->{System.out.println(x + y + z);};
		tl.sum(1, 2, 3);
	}
	
}

interface TestLambda{
	abstract void sum(int a,int b,int c);
}
public static void main(String[] args) {
		//简写
		new Thread(()->{System.out.println("测试lambda_线程");}).start();
		//原匿名内部类
		Thread th = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("原样");
			}
		});
		th.start();
		
	}

三、简写
1、只有一个参数时,可以省略圆括号。(没有参数时,不能省略)
2、方法体只有一个语句,且没有返回值,可以省略花括号、并且可以省略方法体中的分号(不省略时,连续两个分号也可以)
3、方法体只有一句返回语句,同时省略花括号、return关键字和方法体的分号。(不可单独省略)

	public class demo_Lambda_return简写 {
		public static void main(String[] args) {
	//		LambdaJX ljx = (x,y) -> {return x + y;};
			LambdaJX ljx = (x,y) -> x + y;
			System.out.println(ljx.sum(10, 20));
		}
	}
	interface LambdaJX{
		abstract int sum(int a,int b);
	}

方法引用

源地址
一、什么是方法引用?
对lambda表达式进行简写的一个lambda表达式,其中方法引用的操作符是双冒号 “::”。

二、分类
双冒号的左边是类名或者某个对象的引用,右边是方法名

(1)静态方法——类名::静态方法名

(2)非静态方法——类名::实例方法名

(3)非静态方法——对象引用::实例方法名

(4)构造方法——类名::new

(5)类型[]::new
例如:int[] :: new ——x -> new int[x]

其余例子见下方 函数式接口 中的代码

函数式接口

概述

一、简述

1、定义:只有一个抽象方法的接口——函数式接口
2、作用:Lambda表达式实现的前提;函数式编程实现的前提

3、检查该接口是否是函数式接口:@FuctionalInterface。如果不是,编译不通过
4、已经接触过的函数式接口Comparator、Runnable

public class Demo_函数式接口_初识 {
	public static void main(String[] args) {
		//调用getHs方法,此方法返回一个MyInter实现类对象
		MyInter1 hs= getHs();
		//将返回的实现类对象当作参数传给useHs方法,在此方法中调用参数中的test1方法(test1方法在getHs方法中已经重写了)
		useHs(hs);
	}
	
	public static void useHs(MyInter m) {
		m.test1();
	}
	
	public static MyInter getHs() {
		return new MyInter() {
			@Override
			public void test1() {
				System.out.println(111);
			}
		};
	}
}
@FunctionalInterface
interface MyInter {
	public abstract void test1();
	
	public default void test2() {
		System.out.println(222);
	}
}

三、函数式编程
函数:
一种处理数据的逻辑(比如过滤数据,具体的怎么过滤,怎么筛选由使用者自己定义)
Java中:java中没有函数这个概念,所以使用函数式接口来解决这个问题

步骤:
1、使用函数式接口代替函数,该接口就是函数的类型(判断、获取等)
2、将该接口的实现类对象,就是函数类型的对象,以此来表达该函数的具体功能

回顾:
Collections.sort(List list,Comparator c)
学习Collections时学习的sort方法,其中,传入比较器实现类对象( c ),就是一种函数式编程(按照自定义的规则对List集合中的数据进行排序。)

总结:
函数式接口和之前接触的抽象方法、普通的接口有共通之处。之前定义的抽象类、接口是声明某些方法,具体的实现过程由调用者自己重写。而函数式接口是定义某种逻辑,具体的实现逻辑由调用者自己重写

常用函数式接口

Java中定义好了一部分函数式接口,便于使用。

	Consumer<T> :消费型接口——》消耗掉,使用掉
 	 	void accept(T t)
 	Supplier<T> :供给型接口——》获取
 	 	T get()
 	Function<T, R> :函数型接口——》转换类型
 	 	R apply(T t)
 	Predicate<T> :断言型接口——》判断
 	 	boolean test(T t)
一、消费型接口

抽象方法
Consumer void accept(T t)

public class demo_消费型接口 {

	public static void main(String[] args) {
	//调用XF方法,传入参数50和Consumer实现类对象
		
		//匿名内部类
		XF(50,new Consumer<Integer>() {
			//自定义的,消费形式就是用于打印
			@Override
			public void accept(Integer t) {
				System.out.println("购买养乐多,消费" + t + "¥");
			}
		});
		
		//lambda表达式
		XF(50, x -> System.out.println("购买养乐多,消费" + x + "¥"));
		
		//方法引用。这个消费方式,就是打印
		//对象引用 :: 实例方法名
		XF(50,System.out :: println);
	}
	
	public static void XF(int money,Consumer<Integer> con) {
		//将传入的参数money通过Consumer消费类消费
		con.accept(money);
	}
}

二、供给型接口

抽象方法
Supplier T get()

public class demo_供给型接口 {

	public static void main(String[] args) {
		Random r = new Random();
		int ran = r.nextInt(100);
		//匿名内部类
		int b = result(new Supplier<Integer>() {
			@Override
			public Integer get() {
				return ran;
			}
		});	
		System.out.println(b);
		
		//lambda
		int a = result(() -> ran);
		System.out.println(a);
		
		//方法引用。对象引用 :: 非静态方法名
		int c = result(new Random() :: nextInt);
		System.out.println(c);	
	}
	public static int result(Supplier<Integer> su) {
		return su.get();
	}
}
三、函数型接口

抽象方法
Function<T,R> R apply(T t)
默认方法
Function<T, Q> andThen(Function<R, Q> fun)
【待补充】

四、断言型接口

抽象方法
Predicate boolean test(T t)
默认方法
1、Predicate and(Predicate pre)
2、Predicate or(Predicate pre)
3、Predicate negate()判断调用者是否是T数据的函数,返回值也是一个判断T数据的函数
【待补充】

StreammingAPI

高阶抽象的方式对数据进行处理

1、Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
2、Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
3、这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
4、元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到处理结果。

什么是 Stream?
Stream(流)是一个来自数据源的元素队列并支持聚合操作
元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
数据源,流的来源。 可以是集合,数组,I/Ochannel, 产生器generator 等。
聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce,find, match, sorted等。

一、简述
阐述:jdk1.8定义的Stream类型,主要用于对数据进行过滤
优点:便捷

二、如何获取Stream流
1、Collection单列集合,直接调用stream()方法即可。返回的就是Stream类型的对象
2、Map双列集合,不能直接获取,需要先转为单列集合再去获取Stream对象

	1)keySet().stream()获取键Set集合集合,再获取Stream流对象
	2)values().stream()获取值集合,再获取Stream流对象
	3)entrySet().stream()获取键值对set集合,在获取Stream流对象

3、数组,使用Stream中的静态方法of(),Stream.of(数组)

三、常用方法
特点:调用一次后,都不可再使用原Stream引用,而是形成新的Stream引用

分类:

1)终结方法
	使用一次不会返回Stream流对象,不能再调用Stream中的其他方法
2)延迟方法
	使用一次会返回Stream流对象,能再调用Stream中的其他方法(除了终结方法,都是延迟方法)

四、举例

1、终结方法

forEach(Consumer<? super T> con)根据条件进行处理。(将流中的数据,根据con描述的处理方式,进行处理)
long count()统计流中数据个数
public class demo_Stream_终结方法 {

	public static void main(String[] args) throws IOException {
		List<String> names = new ArrayList<String>();
		Collections.addAll(names, "张十三","楚七","赵六","王五","李四");
		
		//终结方法——forEach(),将流中的数据按照Consumer消费型接口中的accept方法操作
		Stream<String> stream = names.stream();
		BufferedWriter bw = new BufferedWriter(new FileWriter("名字.txt"));
		stream.forEach(x -> {
			try {
				bw.write(x);
				bw.newLine();
			} catch (IOException e) {
				e.printStackTrace();
			}
		});
		
		bw.close();
		
		//终结方法——count(),统计个数,返回Long
		Stream<String> st = names.stream();
		long a = st.count();
		System.out.println(a);
	}
}

2、延迟方法

Stream<T> filter(Predicate<? super T> pre)根据条件筛选数据。(根据pre描述的判断条件,对流中的数据进行过滤)
Stream<T> limit(long n)只要前n个数据。(根据参数maxnSize描述的个数,对流中数据进行截取)
Stream<T> skip(long n)只要后n个数据。(跳过参数n描述的个数,流中剩余的是n之后的内容)
Stream<R> map(Function<? super T,R> fun)根据条件转换数据类型。(将流中T类型数据,按照规则,转换为R型数据)
Stream<T> static concat(Stream<T> s1,Stream<T> s2)合并两个Stram流
Stream<T> sorted()按照自然数,排序
public class demo_Stram_延迟方法 {
	/*
	 * 队伍1:齐桓公、宋襄公、晋文公、秦穆公、楚庄王
	 * 孔子、老子、墨子
	 * 队伍2:东伯侯姜桓楚、南伯侯鄂崇禹、西伯侯姬昌、北伯侯崇侯虎
	 * 貂蝉、西施、王昭君、杨贵妃
	 * */
	public static void main(String[] args) {
	//队伍1
		ArrayList<String> names1 = new ArrayList<String>();
		Collections.addAll(names1, "齐桓公","宋襄公","晋文公","秦穆公","楚庄王","孔子","老子","墨子");
		//队伍1只要名字长度为三个字的名字
		Stream<String> sm = names1.stream();
//		Stream<String> sm1 = sm.filter(x -> x.length() ==3);
//		sm1.forEach(System.out :: println);//这是终结方法,下面还要使用sm1
		
		//只要筛选过后的前三人
//		Stream<String> sm2 = sm1.limit(3);
//		sm2.forEach(System.out :: println);
		
		
	//队伍2
		ArrayList<String> names2 = new ArrayList<String>();
		Collections.addAll(names2, "东伯侯姜桓楚","南伯侯鄂崇禹","西伯侯姬昌","北伯侯崇侯虎","貂蝉","西施","王昭君","杨贵妃");
		//只要队伍中的四侯伯
		Stream<String> smm = names2.stream();
//		Stream<String> smm1 = smm.filter(x -> x.contains("伯侯"));
//		smm1.forEach(System.out :: println);
		
		//只要筛选之后的后两个人
//		Stream<String> smm2 = smm1.skip(2);
//		smm2.forEach(System.out :: println);
		
		
	//合并队伍1、2
		Stream<String> ssmm = Stream.concat(sm, smm);
//		ssmm.forEach(System.out ::println);
		
		//合并之后封装到Person对象,存储在ArrayList集合
		ArrayList<Person> personList = new ArrayList<Person>();
//		ssmm.map(x -> new Person(x)).forEach(x -> personList.add(x));
		//简写
		ssmm.map(Person :: new).forEach(personList :: add);
		System.out.println(personList);	
	}
}

class Person{
	private String name;
	public Person() {
		super();
	}
	public Person(String name) {
		super();
		this.name = name;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + "]";
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

陈年_H

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

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

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

打赏作者

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

抵扣说明:

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

余额充值