JAVA8新特性学习入门案例
1.接口的默认方法
允许给接口添加一个非抽象的方法实现,只需要使用default关键字即可,这个特征叫做扩展方法。
public interface InterfaceDemo {
double sum(int a);
default double sqrt(int a){
return Math.sqrt(a);
}
}
实现InterfaceDemo接口时,只需要实现一个sum方法,默认方法sqrt在子类上直接使用。
public class InterfaceTest {
public static void main(String[] args) {
InterfaceDemo interfaceDemo = new InterfaceDemo(){
@Override
public double sum(int a){
return sqrt(a * 100);
}
};
System.out.println(interfaceDemo.sum(100));
System.out.println(interfaceDemo.sqrt(16));
}
}
2.构造引用
使用 :: 关键字来传递方法或者构造者引用。
格式: // 对象名 :: 方法名 // 类名 :: 静态方法名
创建一个类
public class Person {
String firstName;
String lastName;
Person(){
}
Person(String firstName,String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
}
接下来指定一个用来创建Person对象的对象接口。
public interface PersonFactory<P extends Person> {
P creat(String firstName, String lastName);
}
这里我们将他们关联起来,而不是实现一个完整的工厂。
public class PersonTest {
public static void main(String[] args) {
PersonFactory personFactory = Person::new;
Person person = personFactory.creat("sqq", "sxm");
System.out.println(person.firstName);
System.out.println(person.lastName);
}
}
3.lambda表达式
这边我要是使用JAVA8中Predicate(断定和假设的意思)的函数式接口,可以被应用于lambda表达式和方法引用。他包含了一个接口方法和三个默认方法以及一个静态方法。
这边我们使用一个test方法,它是一个写判断逻辑的代码。
public class LambdaDemo1 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
System.out.println(exec(list, new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer%2 == 0;
}
}));
}
private static List<Integer> exec(List<Integer> list, Predicate<Integer> predicate){
List<Integer> list1 = new ArrayList<>();
for (Integer i : list){
if(predicate.test(i)){
list1.add(i);
}
}
return list1;
}
}
接下来把main方法中的变成lambda表达式。把整个输出替换掉。
System.out.println(exec(list, i -> i%2 == 0));
(1)我们一般使用主要是使用他自己的里面的一个方法stream()。
public class LambdaDemo2 {
public static void main(String[] args) {
List<Integer> list= Arrays.asList(1,2,3,4,5);
//1.转成流
Stream<Integer> stream = list.stream();
//过滤方法 只要2的倍数
Stream<Integer> stream1 = stream.filter(i -> i % 2 == 0);
//各个元素 *2 映射
Stream<Integer> stream2 = stream1.map(i -> i * 2);
//收集结果
List<Integer> collect = stream2.collect(Collectors.toList());
System.out.println(collect);
}
}
可以一句写完。
System.out.println(list.stream().filter(i -> i%2 == 0).map(i -> i*2).collect(Collectors.toList()));
(2)各种方法例子集合
public class LambdaDemo3 {
public static void main(String[] args) throws IOException {
ArrayList<String[]> list = new ArrayList<>();
list.add(new String[]{"张三","王五"});
list.add(new String[]{"张三","王五2"});
// 1. flatmap 遍历
List<String> collect = list.stream().flatMap(strings -> stream(strings)).collect(toList());
System.out.println(collect);
// 2. 遍历 foeEach
collect.forEach( s -> System.out.println(s));
//3.map的遍历 接受一个双参数的。。
HashMap<String,String> map = new HashMap<>();
map.put("1","宋");
map.put("2","李");
map.forEach((key,value) -> System.out.println(key+"------"+value));
//求个数 是list的size
System.out.println(list.stream().count());
//去重服 , 张三重复
System.out.println(collect.stream().distinct().collect(Collectors.toList()));
//数组流
int [] array = {3,22,5,3,5,67,3,134,};
List<Integer> integers = asList(2, 3, 4, 6, 34, 21, 3121, 3, 5);
//最大值
System.out.println(Arrays.stream(array).max());
// 文件读取流 , 在遍历
Files.lines(Paths.get("1.txt")).forEach(i -> System.out.println(i));
//使用生产者的接口来随机生成几个整数
Random random = new Random();
Stream.generate(() -> random.nextInt(100)).limit(5).forEach( s -> System.out.println(s));
// :: 关键字方法调用
Stream.generate(() -> random.nextInt(100)).limit(5).forEach( System.out::println);
//格式:
// 对象:: 方法名
// 类型 :: 静态方法名
Arrays.stream(array).filter(i -> i%2 == 0);
// 类名:: 静态方法名
System.out.println(integers.stream().filter(LambdaDemo3::aa).collect(toList()));
}
public static boolean aa(Integer x){
//代码多
return x % 2 == 0;
}
}
4.访问局部变量
使用lambda表达式中访问外层局部变量,可以直接访问被final修饰的的外层局部变量,或者实例的字段以及静态变量。
public class LambdaDemo2 {
interface Convert<T1,T2> {
void convert(int from);
}
public static void main(String[] args) {
final int num = 1;
Convert<Integer,String> s = (param) -> System.out.println(String.valueOf(param + num));
s.convert(2); // 输出结果是3
}
}
lambda表达式的局部变量可以不用final,但是必须不可被后面的代码修改(即隐形的具有fina的语义),如果改的话,会报错,需要添加final。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CRRKsP8e-1574220811019)(C:\Users\M S I\AppData\Roaming\Typora\typora-user-images\1574213074651.png)]
public class LambdaDemo2 {
interface Convert<T1,T2> {
void convert(int from);
}
public static void main(String[] args) {
int num = 1; // 前面默认有final
Convert<Integer,String> s = (param) -> System.out.println(String.valueOf(param + num));
s.convert(2); // 输出结果是3
// num = 5; 注释掉要修改的隐式常量就好了。
}
}
5.访问对象子弹与静态变量
和本地变量不同的是,lambda内部对于实例的字段以及静态变量是即可读有可写,该行为和匿名对象是一致的。
public class LambdaDemo3 {
static int outerStaticNum;
int outerNum;
void testScopes(){
LambdaDemo2.Convert<Integer,String> stringConverter1 = (param) ->{
outerNum = 23;
System.out.println(outerNum);
};
}
LambdaDemo2.Convert<Integer,String> stringConvert2 = (param) -> {
outerStaticNum = 72;
System.out.println(outerStaticNum);
};
}
6.Date API
JAVA8中在包java.time下包含了一组全新的时间日期API。
Clock 时钟
Clock类提供了访问当前日期和时间的方法,Clock是时区敏感的,可以取代System.currentTImeMillis() 来获取当前的微妙数,某一个特定的时间也可以使用instant类来表示,instant类也可以用来创建老的java.util.Date对象。
Clock clock = Clock.systemDefaultZone();
long millis = clock.millis();
System.out.println(millis); // 1574216290018
// 可以代替 Date
Instant instant = clock.instant();
Date date = Date.from(instant);
System.out.println(date); // Wed Nov 20 10:18:10 CST 2019
Timezones时区
在新API中时区使用Zoneld来表示,时区可以很方便的使用静态方法of来获取到。时区定义了带UTS时间的时间差,在instant时间点对象到本地日期对象之间转换的时候是极其重要的。
System.out.println(ZoneId.getAvailableZoneIds());
// [Asia/Aden, America/Cuiaba, Etc/GMT+9, Etc/GMT+8, Africa/Nairobi, America/Marigot, Asia/Aqtau, Pacific/Kwajalein,
// Asia/Chungking, America/Managua, America/Indiana/Petersburg, Asia/Yerevan, Europe/Brussels,
// GMT, Europe/Warsaw, America/Chicago, Asia/Kashgar, Chile/Continental, Pacific/Yap, CET, Etc/GMT-1,
// Etc/GMT-0, Europe/Jersey, America/Tegucigalpa, Etc/GMT-5, Europe/Istanbul, America/Eirunepe, Etc/GMT-4,
// America/Miquelon, Etc/GMT-3, Europe/Luxembourg, Etc/GMT-2, Etc/GMT-9, America/Argentina/Catamarca, Etc/GMT 等等]
ZoneId zone1 = ZoneId.of("Europe/Berlin");
System.out.println(zone1.getRules());
// ZoneRules[currentStandardOffset=+01:00]
LocalTime 本地时间
localTime定义了一个没有时区信息的时间, 例如 晚上10点 , 或者 17:30:15。 下面的例子使用前面代码创建的时区创建了两个本地时间,之后比较时间并以小时和分钟为单位计算两个时间的时间差:
LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS);
LocalDate yesterday = tomorrow.minusDays(2);
LocalDate independenceDay = LocalDate.of(2014, Month.JULY, 4);
DayOfWeek dayOfWeek = independenceDay.getDayOfWeek();
System.out.println(dayOfWeek); // FRIDAY
时间这种东西,现在看了,不一定用得上,什么时候用,到时看看就行。新特性,主要还是lambda表达式。