jdk1.8版本是2014發布的,自java 1.5以來最具有革命性的版本了,在語言、編譯器、類庫、開發工具以及Java虛擬機等方面都帶來了不少新特性。
並且版本穩定,已經廣泛應用於企業級開發。這些新特性能夠幫助開發人員提升編碼效率,加深對java的理解,因此作為一個合格的java程序員,掌握
和理解這些新特性是很有必要的。下面開始介紹這些新特性。
- lambda表達式
lambda表達式是將函數作為參數進行傳遞,從而實現了函數式編程(函數式編程在js中廣泛應用),看下面一段傳統方式創建線程的代碼:
Runnable runnable1 = new Runnable() { @Override public void run() { System.out.println("runnable..."); System.out.println("run...."); }
利用lambda表達式可以這樣寫
Runnable runnable2 = ()->{ System.out.println("runnable..."); System.out.println("run...."); };
其中 () 代表參數, {}代表函數主體。表現為 (Type1 parameter1,Type2 parameter2........)->{statment1;statmenet2;......}
什么情況適用於lambda表達式呢?答案是 :能夠接收Lambda表達式的參數類型,是一個只包含一個方法的接口,稱為函數式接口,為此jdk1.8推出了一種標記注解@FunctionalInterface
@FunctionalInterface public interface Animal { String talk(String name); } //main Animal animal = (name)->"animal的name是:"+name; System.out.println(animal.talk("dog..."));
- 方法引用
Lambda方法體中的內容已經有實現,可以使用方法引用。前提是
1. Lambda體中的調用方法的參數,返回值要和該Lambda對應的函數式接口中抽象方法的參數和返回值一致
語法格式:
對象::實例方法名 Consumer<String> con = System.out:print
類::靜態方法名 Comparator<Integer> com = Integer::compare;
類::實例方法名 BiPredicate<String,String> biPredicate = String::equals; == biPredicate = (x,y)->x.equals(y);
前提是參數列表中第一個參數是實例方法的調用者,第二個參數是實例方法的參數
或者第一個參數是實例方法的調用者,沒有第二個參數 list.stream().map(String::toUpperCase).forEach(System.out::println); == list.stream().map(x->x.toUpperCase()).forEach(System.out::println);
若對參數有任何修改,則不能使用方法引用,而需鍵入完整地lambda表達式,如下所示:
list.forEach((String s) -> System.out.println("*" + s + "*"));
- 構造器引用
語法格式:類名::new
1.無參構造器
Supplier<Object> supplier = Object::new == Supplier<Object> supplier = ()->new Object()
2.一個參數的構造器
Function<String,String> fun = String::new == Function<String,String> fun = (p)-> new String(p)
import java.util.Arrays; import java.util.List; /** * Created by IntelliJ IDEA. * User: chenzhubing * Date: 2019/6/27 */ public class MyConsumer { public static void main(String[] args) { List<String> list = Arrays.asList("a","b","c"); list.forEach(x->MyConsumer.print(x)); list.forEach(MyConsumer::print); new MyConsumer().start(); } public void start(){ List<String> list = Arrays.asList("a1","b1","c1"); list.forEach(x->{new MyConsumer().print1(x);}); list.forEach(new MyConsumer()::print1); } public void print1(String str){ System.out.println(str); } public static void print(String str){ System.out.println(str); } }
- 內置核心接口
- consumer<T> 消費型接口:void accept(T t)
- Supplier<T> 供給型接口:T get()
- Function<T,R> 函數型接口:R apply(T t)
- R apply(T t)斷言型接口:boolean test(T t)
Consumer:有參數,無返回值
/** * * @param param * @param con */ public void testConsumerInterface(Integer param, Consumer<Integer> con){ con.accept(param); } test.testConsumerInterface(10,(p)-> System.out.println(p));
Supplier:無入參,有返回值
/** * * @param supplier * @return */ public List<Integer> testSupplierInterface(Supplier<Integer>supplier){ List<Integer> list = new ArrayList<>(); list.add(supplier.get()); return list; } List result = test.testSupplierInterface(()->100); result.forEach(System.out::println);
Function:有入參,有出參
/** * * @param input * @param fun * @return */ public List<String> testFunctionInterface(Integer input,Function<Integer,String> fun){ List<String> list = new ArrayList<>(); list.add(fun.apply(input)); return list; } result = test.testFunctionInterface(100,p->p+"hello,world"); result.forEach(System.out::println);
Predicate : 有入參,返回值是boolean
/** * * @param input * @param predicate * @return */ public List<Integer> testPredicateInterface(Integer input, Predicate<Integer> predicate){ List<Integer> list = new ArrayList<>(); if(predicate.test(input)){ list.add(input); } return list; } result = test.testPredicateInterface(100,p->p>10); result.forEach(System.out::println);
- stream
jdk1.8新推出來的stream(和IO流沒有關系)是針對Collection的增強。它專注於對集合對象進行各種非常便利、高效的聚合操作。配合lambda表達式能提升編碼效率和程序的可讀性。
1.Stream不會自己存儲元素
2.Stream不會改變源對象,會返回一個新的Stream
3.Stream操作是延遲執行的,意味着需要結果的時候才執行
public class Person { private String name; private String nickName; private int gender; //0-男 1-女 private int salary; //薪水 public String getName() { return name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", nickName='" + nickName + '\'' + ", gender=" + gender + ", salary=" + salary + '}'; } public Person(){ } public static Person getPerson(){ return new Person(); } public Person(String name, String nickName, int gender, int salary) { this.name = name; this.nickName = nickName; this.gender = gender; this.salary = salary; } public void setName(String name) { this.name = name; } public int getGender() { return gender; } public void setGender(int gender) { this.gender = gender; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } public String getNickName() { return nickName; } public void setNickName(String nickName) { this.nickName = nickName; } } List<Person> list = new ArrayList<Person>(){ { add(new Person("張三","zhangsan",0,10)); add(new Person("李四","zhangsan",1,20)); add(new Person("王五","wangwu",0,30)); add(new Person("小劉","xiaoliu",1,40)); add(new Person("三木","sanmu",0,50)); } };
常用的操作有:filter,limit,skip,distinct,min,max,flatMap,sorted...........................
1)min :求集合中最小對象
Object obj = list.stream().min((p1,p2)->(p1.getSalary()-p2.getSalary())).get();
2 ) max : 求集合最大對象
Object obj = list.stream().max((p1,p2)->(p1.getSalary()-p2.getSalary())).get();
3 ) filter :根據條件過濾
list.stream().filter((p)->(1==p.getGender()))
4 ) limit: 取集合中的前多少個元素
list.stream().filter(
(p)->(1==p.getGender())
).limit(5)
5 ) sorted :排序
list.stream().sorted(
(p1,p2)->p1.getNickName().compareTo(p2.getNickName())
).forEach(
x-> System.out.println(x.getName())
)
6)allMatch
boolean r = list1.stream().allMatch(x->x.equals("a"));
System.out.println(r);
7)anyMatch
r = list1.stream().anyMatch(x->x.equals("e"));
System.out.println(r);
8)noneMatch
r = list1.stream().noneMatch((x)->x.equals("a"));
System.out.println(r);
9)count
long count = list1.stream().count();
System.out.println(count);
10 ) map: 歸類,結果一般是一組數據
list1.stream().map(x->x.getSalary()).forEach(x-> System.out.println(x)); //將person中salary歸類成一組數據
List<Integer> mapList = list1.stream().map(x->x.getSalary()).map(x->x-10).collect(Collectors.toList()); //將person中的salary歸類成一組數據,並將salary-10
11 ) reduce: 歸約 ,用來計算結果,結果是一個數值
Integer sum = list1.stream().map(x->x.getSalary()).reduce(0,(x,y)->x+y); //求總和,其中0是基准
int max = list1.stream().map(x->x.getSalary()).reduce(0,(x,y)->Integer.max(x,y));
12) collect : 收集,將處理后的結果輸出到新的集合中,如list,set,map等 ;或者返回處理的結果,如求集合的個數,平均值等
list.stream().filter().collect(Collectors.toList())
list.stream().filter().collect(Collectors.toSet())
Long count = list1.stream().filter(p->p.getGender()==0).collect(Collectors.counting());
Double sumSalary = list1.stream().collect(Collectors.summingDouble(x->x.getSalary()));
double red = list2.stream().collect(Collectors.maxBy(Double::compareTo)).get();
double red = list2.stream().collect(Collectors.minBy(Double::compareTo)).get();
Map<Double,List<Double>> map = list2.stream().collect(Collectors.groupingBy(x->x)); //分組
Map<Double,Map<Double,List<Double>>> map1 = list2.stream().collect(Collectors.groupingBy(x->x,Collectors.groupingBy(x->x))); //多級分組
str = list1.stream().collect(Collectors.joining(",","start=","end=")); //結果集拼接
13 ) toMap
Map map = list1.stream().filter((p)->(1==p.getGender())).limit(2).collect(Collectors.toMap(Person::getName,Person::getNickName)); // key=name ,value=nickname
map = list1.stream().collect(Collectors.toMap(x->x.getNickName(),Function.identity())); //key=nickname, value = key對應的對象;注意key重復會拋出異常
map = list1.stream().collect(Collectors.toMap(x->x.getNickName(),Function.identity(),(oldValue,newValue)->newValue)); //key重復, 取新的key
map = list1.stream().collect(Collectors.toMap(x->x.getNickName(),Function.identity(),(oldValue,newValue)->oldValue)); //key重復, 取舊的key
- Optional
Optional的主要用處是可以有效的避免NullPointerException,配合lambda可以減少代碼中大量的空指針判斷,總之,代碼更加優雅。
1) 創建Optional對象 :主要有兩種方式
1.1 要求T非空,這種方式實際意義不大
Optional<T> op = Optional.of(T);
1.2 可以包裝一個null的對象
Optional<T> op = optional.ofNullable(T);
2) ifPresent
op.ifPresent(p1->p1.setName("hello"));
如果T存在,則執行 p1->p1.setName("hello"),相當於
if(T != null){
p1.setName("hello");
}
3) orElse
如果T存在,返回;如果T不存在,則返回orElse里面的對象
op.orElse(Person.getPerson());
等價於
if(op.ifPresent()){
return op.get();
}else{
Person.getPerson();
}
4) orElseGet
如果T存在,返回;如果T不存在,則執行orElseGet里面的內容,並返回一個對象
op.orElseGet(()->{
System.out.println("helloworld");
System.out.println("sssssssssss");
return new Person();
});
5) orElseThrow
如果T存在,返回;如果T不存在,則執行orElseThrow里面的內容,並返回一個異常
op.orElseThrow(()->{
System.out.println("exception");
return new ArithmeticException("null");
});