JAVA 8 的新特性
Java8的新特性有:默认方法、函数式接口、lambda表达式、方法引用、Stream、Optional、日期API。
一、默认方法:
接口中的方法可以有方法体,但是必须要有static或者default修饰,其他的方法都为抽象方法,由static修饰的方法不能被子接口继承 、方法不能被覆写,只能通过类名.方法名调用;由default修饰的方法可以被子接口继承,也可以被覆写,调用通过实现类的对象调用。
二、函数式接口:
接口中有且仅有一个抽象方法,一般都有@FuntionalInterface注解,即使没有注解它还是函数式接口。
常见的函数式接口:Comparetor、Runnable。
三、lambda表达式:
可以看成是对匿名内部类的简写,使用lambda表达式的接口必须为函数式接口;
注:匿名内部类会编译产生两个class文件,但lambda表达式只会编译产生一个class文件。
(参数1,参数2…)表示参数列表;->表示连接符;{}内部是方法体
1、=右边的类型会根据左边的函数式接口类型自动推断;
2、如果形参列表为空,只需保留();
3、如果形参只有1个,()可以省略,只需要参数的名称即可;
4、如果执行语句只有1句,且无返回值,{}可以省略,若有返回值,则若想省去{},则必须同时省略return,且执行语句也保证只有1句;
5、形参列表的数据类型会自动推断;
6、lambda表达式中使用的局部变量默认会被final修饰,不管这个局部变量是在lamdba表达式里定义的还是在表达式外定义的。因此只要是lambda表达式中使用过的局部变量就不能再修改了,不管在什么位置。
四、方法引用:
4.1 构造方法引用:
//匿名内部类 PersonFacotry facotry = new PersonFacotry() { @override public Person createPerson(String name, Integer age){ //其他操作 return new Person (name, age); } }; //lambda表达式写法 PersonFacotry facotry1 = (name, age) -> new Person (name, age); //lambda表达式简写(这种写法的函数式接口有几个参数,就调用其对应参数个数的构造方法) PersonFacotry facotry2 = Person:: new; Person person = facotry.createPerson ( name: "某某某", age: 100) ; System.out.println(person);
4.2静态方法引用
public class Test{ public static void main(string[] args) { //匿名内部类方式 Parseinterface pil = new ParseInterface(){ @override public int parse(string str) { return Integer.parselnt(str); } }; // Lambda表达式常规写法 ParseInterface pi2 = str->Integer.parseInt(str); // Lambda表达式简写 ParseInterface pi3 = Integer::parseInt; } }
4.3实例方法引用
Java1.8提供了一个函数式接口Function,接受两个参数
匿名内部类方式
string str ="Hello.world"; //匿名内部类的方式 Function<String,Boolean> func1= new Function<String,Boolean> (){ @override public Boolean apply(strinq suffix) { return str.endswith (suffix); } };
Lambda表达式常规写法
// Lambda表达式常规写法 String str = "Hello.world"; Function<String,Boolean> func3 = t -> str.endsWith(t); System.out.println(func3.apply("world"));
Lambda表达式简写
// Lambda表达式常规写法 String str = "Hello.world"; Function<String,Boolean> func2 = t -> str::endsWith; System.out.println(func2.apply("world"));
五、Stream:
Java 8 API添加了一个新的抽象称为流Stream,Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
注意:和IO中的流是完全不一样的。
在 Java 8 中, 集合接口有两个方法来生成流:
stream() − 为集合创建串行流。(常用)
parallelStream() − 为集合创建并行流。
Stream常用方法:
ForEach:
Stream 提供了新的方法 'forEach' 来迭代流中的每个数据。以下代码片段使用 forEach 输出了10个随机数:
Random random = new Random(); random.ints().limit(10).forEach(System.out::println);
map:
map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); // 获取对应的平方数 List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
filter:
filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
int count = strings.stream().filter(string -> string.isEmpty()).count();
limit:
limit 方法用于获取指定数量的流。 以下代码片段使用 limit 方法打印出 10 条数据:
Random random = new Random(); random.ints().limit(10).forEach(System.out::println);
sorted:
sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:
Random random = new Random(); random.ints().limit(10).sorted().forEach(System.out::println);
并行(parallel)程序:
parallelStream 是流并行处理程序的代替方法。以下实例我们使用 parallelStream 来输出空字符串的数量:
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); // 获取空字符串的数量 int count = strings.parallelStream().filter(string -> string.isEmpty()).count();
我们可以很容易的在顺序运行和并行直接切换。
Collectors:
Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList()); System.out.println("筛选列表: " + filtered); String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("合并字符串: " + mergedString);
六、Optional:
Optional对象可以为空,所以Optional 类的引入很好的解决空指针异常。
通过以下实例来了解Optional类的使用:
Public class User{ private String name; private String password; .... }
以往的判断方式:
public class Mytest{ public static void main(String[] args){ User user = new User(); User.setPassword(“admin”); String name = getPwd(user); System.out.println(name); } public static String getPwd(User u){ if(u==null){ return “unknown”; } return u.getPassword(); }
使用Optional:
public static String getPwd(User u){ return Optional.ofNullable(u) .map(user->user.getPassword()) .orElse(“unknown”); };
七、日期Api:
Jdk1.8给我们提供了三个本地日期时间类:LocalDate、LocalTime 和 LocalDateTime 类。
在不需要处理时区问题的时候,使用本地日期时间API(LocalDate、LocalTime 和 LocalDateTime) :
// 获取当前的日期时间 LocalDateTime currentTime = LocalDateTime.now(); System.out.println("当前时间: " + currentTime); LocalDate date1 = currentTime.toLocalDate(); System.out.println("date1: " + date1); Month month = currentTime.getMonth(); int day = currentTime.getDayOfMonth(); int seconds = currentTime.getSecond(); System.out.println("月: " + month +", 日: " + day +", 秒: " + seconds);
在需要处理时区的时候,使用时区的日期时间API(ZonedDateTime ):
ZonedDateTime dd= ZonedDateTime.now(); System.out.println(dd); ZonedDateTime date1 = ZonedDateTime.parse(dd.toString()); System.out.println("date1: " + date1); ZoneId id = ZoneId.of(ZoneId.SHORT_IDS.get("CTT")); System.out.println("ZoneId: " + id); ZoneId currentZone = ZoneId.systemDefault(); System.out.println("当期时区: " + currentZone);