jdk1.8新特性

jdk1.8特性

函数式接口

函数接口是只有一个抽象方法的接口,用作lambda表达式返回类型,该类型的接口都有@FunctionalInterface这个注解。虽然该类型接口只有一个抽象方法,但可以有多个默认实现方法和静态方法
默认方法
为了以兼容方式改进API,Java 8中加入了默认方法。主要是为了支持库设计师,让他们能够写出更容易改进的接口。具体写法是在接口中加default关键字修饰,一般正常开发中不会使用到。
由于类可以实现多个接口,也可以继承类,当接口和类中有相同的方法名时会使用那个类或者接口的实现。
(1) 类中的方法优先级最高。类或父类中声明的方法的优先级高于任何声明为默认方法的优先级。
(2) 如果无法依据第一条进行判断,那么子接口的优先级更高:方法名相同时,优先选择拥有最具体实现的默认方法的接口,即如果B继承了A,那么B就比A更加具体。
(3) 最后,如果还是无法判断,继承了多个接口的类必须通过显式覆盖和调用期望的方法, 显式地选择使用哪一个默认方法的实现。不然编译报错。
自定义函数接口

 @FunctionalInterface
public interface TestFunction {
	//@FunctionalInterface 表示该接口为函数接口
	/** 函数接口特点
	 * 只能有一个接口
	 * 可以有多个默认实现方法和静态方法
	 */
	 String getName(String name);
	 
	 /** 该方法来自顶层object的equals
	 * @param obj
	 * @return
	 */
	boolean equals(Object obj);
	 
	default String then() {
		return "中国";
	}
	default String then2() {
		return "my world";
	}
	
	static String getHost() {
		return "localhost";
	}
}

lambda表达式

lambda表达式本质上是一段匿名内部类,也可以是一段可以传递的代码
语法
完整的Lambda表达式由三部分组成:参数列表、箭头、声明语句;

(Type1 param1, Type2 param2, ..., TypeN paramN)> { statment1; statment2; //............. return statmentM;}

简化:
1.绝大多数情况,编译器都可以从上下文环境中推断出lambda表达式的参数类 型,所以参数可以省略;
2.当lambda表达式的参数个数只有一个,可以省略小括号:

param1 ‐> { statment1; statment2; //............. return statmentM;}
  1. 当lambda表达式只包含一条语句时,可以省略大括号、return和语句结尾的分号:
param1 ‐> statment

案例

		//内部类创建多线程
		Thread thread = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("匿名内部类当前线程"+Thread.currentThread().getName());
			}
		});
		thread.start();

		//lambda创建多线层
		Thread tlam = new Thread(() -> {
			System.out.println("lambda当前线程"+Thread.currentThread().getName());
		});
		tlam.start();
		
		//lambda简化
		/*
		 * 如果 当lambda表达式只包含一条语句时,可以省略大括号、return和语句结尾的 分号
		 */
		Thread tt = new Thread(() ->  System.out.println("lambda简化当前线程"+Thread.currentThread().getName()));
		tt.start();

demo2:在java.util.function包下有着许多函数式接口例如Consumer
在这里插入图片描述

package lambda;

import java.util.function.Consumer;

public class Test5 {
	
	private static void consumer(String something,Consumer<String> con) {con.accept(something);}
	private static void doubleConsumer(String something,Consumer<String> con1,Consumer<String> con2) {con1.andThen(con2).accept(something);}
	
	public static void main(String[] args) {
		//完整的lambda表达式由三部分组成:参数列表、箭头、声明语句
		consumer("中国", (String s)->{
			System.out.println("我在"+s);
		});
		//简化1 参数类型可以省略,如果参数只有一个那么小括号也能省略
		consumer("中国", s->{
			System.out.println("我在"+s);
		});
		//简化2 当lambda表达式只包含一条语句时,可以省略大括号、return和语句结尾的 分号
		consumer("中国", s->System.out.println("我在"+s));
		
		//简化3  方法引用  如果一个Lambda代表的只是“直接调用这个方法”,那 最好还是用名称来调用它,而不是去描述如何调用它   所以方法引用只是在内容中只有一个表达式的简写
		consumer("中国", System.out::println);
		
		doubleConsumer("中国",
				s->System.out.println("我再"+s),
				s->System.out.println(s+"NB")
		);
		
	}
	
}

局部变量限制
Lambda表达式也允许使用自由变量(不是参数,而是在外层作用域中定义的变量),就像匿名类一样。 它们被称作捕获Lambda。 Lambda可以没有限制地捕获(也就是在其主体中引用)实例变量和静态变量。但局部变量必须显式声明为final,或事实上是final。
为什么局部变量有这些限制?
实例变量和局部变量背后的实现有一个关键不同。实例变量都存储在堆中,而局部变量则保存在栈上。如果Lambda可以直接访问局部变量,而且Lambda是在一个线程中使用 的,则使用Lambda的线程,可能会在分配该变量的线程将这个变量收回之后,去访问该变 量。因此, Java在访问自由局部变量时,实际上是在访问它的副本,而不是访问原始变 量。如果局部变量仅仅赋值一次那就没有什么区别了——因此就有了这个限制。
demo3:

package lambda;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/** lambda局部变量的限制
 * @author Admin
 *
 */
public class Test3 {
	 // Lambda可以没有限制地捕获(也就是在其主体 中引用)实例变量和静态变量。但局部变量必须显式声明为final,或事实上是final
	public Map<String, Object> map = new HashMap<>();
	public static  Map<String, Object> mapst = new HashMap<>();
	
	public static void main(String[] args) {
		Map<String, Object> mm = new HashMap<>();
		mm.put("111", 111);
		mapst.put("111", 111);
		Integer a = 22;
		new Thread(() -> {
			//没有限制的使用实例变量和静态变量
			mapst.put("aa", 11);
			mapst = new HashMap<>();
			new Test3().map.put("bb", 22);
			//局部变量的限制
//			a =33; //报错  Integer a 是final 不能修改a的值 
			//map可以修改参数,不能修改引用地址
			mm.put("mm", 222);
//			mm = new HashMap<>();   //报错
			
		}).start();
	}
}

方法引用

方法引用的基本思想是,如果一个Lambda代表的只是“直接调用这个方法”,那最好还是用名称来调用它,而不是去描述如何调用它。事实上,方法引用就是让你根据已有的方法实现来创建Lambda表达式。但是,显式地指明方法的名称, 你的代码的可读性会更好。所以方法引用只是在内容中只有一个表达式的简写。
demo

package method;

import java.util.Arrays;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/** 方法引用案例
 * @author Admin
 *
 */
public class Test1 {
	/** 方法引用注意事项
	 *  1: lambda实现体中调用方法的参数列表与返回值类型,与函数式接口中接口的参数列表和返回值类型相同
	 *  2: 若lambda参数列表中的第一个参数是实例方法的调用者,第二个参数是实例方法的参数时
	 * 	 满足两个条件中任意一个 可以使用
	 */
	public static void main(String[] args) {
		//lambda
		Consumer<Integer> con = s->{System.out.println(s);};
		con.accept(100);
		
		//方法引用简化  --实例方法
		Consumer<Integer> con2 = System.out::println;
		con2.accept(10000);
		
		//静态方法  满足第一个条件
		BiFunction<Integer, Integer, Integer> biFun = (x,y)->{ return Integer.compare(x, y);};
		BiFunction<Integer, Integer, Integer> biFun2 = Integer::compare;
		Integer apply = biFun2.apply(100, 20);
		System.out.println(apply);
		
		//实例方法 满足第二个条件
		BiFunction<String, String, Boolean> biFun3 = (x,y)->x.equals(y);
		BiFunction<String, String, Boolean> biFun4 = String::equals;
		Boolean bo = biFun4.apply("aa", "bb");
		System.out.println(bo);
		
		//构造方法引用
		Supplier<String> supplier = ()-> new String();
		Supplier<String> supplier2 =String::new;
		
		//构造方法引用--带一个参数
		Function<String, Integer> fun = x-> new Integer(x);
		Function<String, Integer> fun2 =Integer::new;
		Integer aa = fun2.apply("10");
		System.out.println(aa);
		
		//数组引用
		Function<Integer, String[]> fun3 = a->new String[a]; 
		Function<Integer, String[]> fun4 = b->new String[b];
		String[] ss = fun4.apply(10);
		System.out.println(Arrays.toString(ss));
	}

}

StreamAPI

介绍
流是Java API的新成员,它允许你以声明性方式处理数据集合(通过查询语句来 表达,而不是临时编写一个实现)。就现在来说,你可以把它们看成遍历数据集 的高级迭代器。此外,流还可以透明地并行处理,你无需写任何多线程代码了!
注意
每个流只能使用一次,如果重复使用编译不会报错,但运行会报错
stream has already been operated upon or closed
常用StreamAPI案例

package stream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Test1 {
	private static boolean compares30(Integer x) {
		if (x>=30) {
			return true;
		}
		return false;
	}
	private static boolean compares70(Integer x) {
		if (x<=70) {
			return true;
		}
		return false;
	}
	//测试过滤
	private static void testFilter() {
		List<Integer> list = new ArrayList<>();
		list.add(10);
		list.add(30);
		list.add(55);
		list.add(96);
		list.add(24);
		list.add(27);
		list.add(63);
		list.add(52);
		list.add(77);
		list.add(22);
		list.add(2);
		list.add(18);
		Stream<Integer> stream = list.stream();
//		stream.filter(a->compares30(a)).filter(a->compares70(a)).forEach(System.out::println);
		stream.filter(Test1::compares30).filter(Test1::compares70).forEach(System.out::println);

	}

	//获取流
	private static void testGetStream() {
		List<Object> list = new ArrayList<>();
		Stream<Object> listStream = list.stream();

		Set<Object> set = new HashSet<>();
		Stream<Object> setStream = set.stream();

		Map<String, Object> map = new HashMap<>();
		Stream<String> keyStream = map.keySet().stream();
		Stream<Object> valueStream = map.values().stream();

		String[] aff = {"你好","世界","中国"};
		Stream<String> stream = Stream.of(aff);

	}

	//类型转换
	private static void streamMap() {
		Stream<String> stream = Stream.of("11","22","33","44","55");
		stream.map(Integer::valueOf).forEach(System.out::println);
	}

	//数据截取limit
	private static void limit() {
		Stream<String> stream = Stream.of("11","22","33","44","55");
		stream.limit(2).forEach(System.out::println);
	}

	//跳过操作
	private static void skip() {
		Stream<String> stream = Stream.of("11","22","33","44","55");
		stream.skip(2).forEach(System.out::println);

	}

	//连接两个流concat
	private static void concat() {
		Stream<String> stream1 = Stream.of("11","22");
		Stream<String> stream2 = Stream.of("33","44","55");
		Stream.concat(stream1, stream2).forEach(System.out::println);
	}

	//规约操作
	private static void reduce() {
		List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
		Stream<Integer> stream = list.stream();
		Integer integer = stream.reduce(0,(x,y)->x+y);
		System.out.println(integer);
	}

	//去重
	private static void distinct() {
		List<Integer> list = Arrays.asList(1,2,2,4,4,6,8,8,9);
		list.stream().distinct().forEach(System.out::println);
	}

	//list 转   map
	private static void listToMap() {
		List<User> userList = new ArrayList<>();
		userList.add(new User(1L,"张三"));
		userList.add(new User(2L,"李四"));
		userList.add(new User(3L,"张飞"));
		userList.add(new User(4L,"关羽"));

		Map<Long, User> map = userList.stream().collect(Collectors.toMap(User::getId,Function.identity()));
		map.forEach((x,y)->System.out.println(x+":"+y));
	}

	//获取 list中实体类的id作为集合
	private static void mapToList() {
		List<User> userList = new ArrayList<>();
		userList.add(new User(1L,"张三"));
		userList.add(new User(2L,"李四"));
		userList.add(new User(3L,"张飞"));
		userList.add(new User(4L,"关羽"));
		List<Long> list = userList.stream().map(User::getId).collect(Collectors.toList());
		list.forEach(System.out::println);

	}

	private static Predicate<User> predicate(User user) {
		return t -> {
			if (t.getId().equals(user.getId()) && t.getName().equals(user.getName())) {
				return true;
			}

			return false;
		};
	}
	//匹配
	private static void anyMatch() {
		List<User> userList = new ArrayList<>();
		userList.add(new User(1L,"张三"));
		userList.add(new User(2L,"李四"));
		userList.add(new User(3L,"张飞"));
		userList.add(new User(4L,"关羽"));
		User user = new User(1L,"张三");

		boolean anyMatch = userList.stream().anyMatch(predicate(user));
		System.out.println(anyMatch);
	}

	public static void main(String[] args) {
		testFilter();
	}

}

时间日期API

1 * 之前使用的java.util.Date月份从0开始,我们一般会+1使用,很不方便, java.time.LocalDate月份和星期都改成了enum
2 * java.util.Date和SimpleDateFormat都不是线程安全的,而LocalDate和LocalTime 和最基本的String一样,是不变类型,不但线程安全,而且不能修改。
3 * java.util.Date是一个“万能接口”,它包含日期、时间,还有毫秒数,更加明确需求取 舍
4 * 新接口更好用的原因是考虑到了日期时间的操作,经常发生往前推或往后推几天的情 况。用java.util.Date配合Calendar要写好多代码,而且一般的开发人员还不一定能写对。

1.8之前JDK自带的日期处理类非常不方便,不过1.8出现之后这个改观了很多,比如日期时间的创建、比 较、调整、格式化、时间间隔等。 这些类都在java.time包下。比原来实用了很多。
介绍几个常用类:
LocalDate/LocalTime/LocalDateTime
LocalDate为日期处理类、LocalTime为时间处理类、LocalDateTime为日期时间处理类, 方法都类似, now相关的方法可以获取当前日期或时间,of方法可以创建对应的日期或时间,parse方法 可以解析日期或时间,get方法可以获取日期或时间信息,with方法可以设置日期或时间信 息,plus或minus方法可以增减日期或时间信息;
TemporalAdjusters
这个类在日期调整时非常有用,比如得到当月的第一天、最后一天,当年的第一天、最后一 天,下一周或前一周的某天等。
**DateTimeFormatter **以前日期格式化一般用SimpleDateFormat类,但是不怎么好用,现在1.8引入了 DateTimeFormatter类,默认定义了很多常量格式(ISO打头的),在使用的时候一般配合 LocalDate/LocalTime/LocalDateTime使用。
API案例

package localdate;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;

public class Test1 {
	public static void main(String[] args) {
		//获取当前日期
		LocalDate toDate = LocalDate.now();
		//根据年月日生成时间
		LocalDate of = LocalDate.of(2021, 8, 27);
		//根据字符串获取日期
		LocalDate date = LocalDate.parse("2021-08-27");

		//===============日期计算==========
		//获取本月第一天
		LocalDate day1 = toDate.with(TemporalAdjusters.firstDayOfMonth());
		//获取今年第一天
		LocalDate day2 = toDate.with(TemporalAdjusters.firstDayOfYear());
		//获取明年第一天
		LocalDate day3 = toDate.with(TemporalAdjusters.firstDayOfNextYear());
		//下个月第一天
		LocalDate day4 = toDate.with(TemporalAdjusters.firstDayOfNextMonth());
		//获取本月
		int monthValue = toDate.getMonthValue();
		//一年中的第几天
		int dayOfYear = toDate.getDayOfYear();

		LocalDate localDate1 = LocalDate.parse("2020-08-28");
    	LocalDate LocalDate2 = LocalDate.parse("2021-08-28");
    	//两个日期年份相差
    	int years = localDate1.until(LocalDate2).getYears();
    	//两个日期月份相差(不计算年份)
    	int months = localDate1.until(LocalDate2).getMonths();
    	//两个日期天数相差(不计算年份和月份)
    	int days = localDate1.until(LocalDate2).getDays();
    	
    	//计算两个日期天数相差
    	long dayLong = localDate1.until(LocalDate2, ChronoUnit.DAYS);
    	//两个日期月份相差
    	long monthLong = localDate1.until(LocalDate2, ChronoUnit.MONTHS);
    

		//============时间====================
		//带有纳秒
		LocalTime now = LocalTime.now();
		//不带纳秒
		LocalTime now2 = LocalTime.now().withNano(0);
		//根据传入的时分秒获取时间
		LocalTime now3 = LocalTime.now().withHour(21).withMinute(30).withSecond(30).withNano(0);

		//获取毫秒时间戳
		long epochMilli = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
		long currentTimeMillis = System.currentTimeMillis();
		long time = new Date().getTime();
		//获取秒时间戳
		long epochSecond = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
		//时间戳转指定格式日期
		DateTimeFormatter df = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss");
		String format = df.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(1630057193027L), ZoneId.of("Asia/Shanghai")));
		
		//解析字符串to时间
		DateTimeFormatter df2 = DateTimeFormatter.ofPattern("YYYY年MM月dd日 HH:mm:ss");
		String format2 = df2.format(LocalDateTime.now());
		LocalDateTime parse = LocalDateTime.parse("2021年08月27日 18:04:48", df2);
		System.out.println(format2);
		System.out.println(parse);
		
		//加上或减去指定天数	
		LocalDateTime now = LocalDateTime.now();
		DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		//五天后
		LocalDateTime plusDays = LocalDateTime.now().plusDays(5);
		//五天前
		LocalDateTime minusDays= LocalDateTime.now().minusDays(5);
		
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值