JDK8新特性詳解
1、Lambda演變過程
@Data @ToString @NoArgsConstructor @AllArgsConstructor public class Student { //名字 private String name; //性別 private String sex; //薪水 private int salary; //年齡 private int age; //星座 private String star; }
1.1、普通篩選
將這個集合遍歷,然後依次的判斷,這是最為普通的一種方式。
@Test public void test1(){ //首先建立一個 List<Student> list = Arrays.asList( new Student("九天","男",5000,18,"天秤座"), new Student("十夜","男",4000,16,"雙魚座"), new Student("十一郎","男",3000,24,"水瓶座") ); List<Student> result = new ArrayList<>(); for (Student student:list){ if ("天秤座".equals(student.getStar())){ result.add(student); } } System.out.println(result); }
1.2、匿名內部類篩選
透過匿名內部類的方法,在內部類中新增判斷條件進行篩選,首先建立一個公共介面:
public interface FilterProcess<T> { boolean process(T t); }
接下來透過一個公共函式,對集合以及篩選條件做一個共同方法,篩選到班級裡星座是天秤星座的學生
public List<Student> filterStudent(List<Student> students, FilterProcess<Student> mp){ List<Student> list = new ArrayList<>(); for (Student student : students) { if(mp.process(student)){ list.add(student); } } return list; }
最後是透過匿名內部類和該方法得到結果:
@Test public void test2(){ List<Student> students = Arrays.asList( new Student("九天","男",5000,18,"天秤座"), new Student("十夜","男",4000,16,"雙魚座"), new Student("十一郎","男",3000,24,"水瓶座") ); List<Student> list = filterStudent(students, new FilterProcess<Student>() { @Override public boolean process(Student student) { return student.getStar().equals("天秤座"); } }); for (Student student : list) { System.out.println(student); } }
結果如圖:
1.3、半Lambda方法
但是透過這兩種程式碼都是很多,所以java8在這一點上提供了對集合篩選最大程度的刪減程式碼,就是第三種方法。第三種方法:透過Lambda直接判斷,一步到位,不需要在寫其他的方法。
@Test public void test3(){ List<Student> list = Arrays.asList( new Student("九天","男",5000,18,"天秤座"), new Student("十夜","男",4000,16,"雙魚座"), new Student("十一郎","男",3000,24,"水瓶座") ); List<Student> result = filterStudent(list,(e)->e.getStar().equals("天秤座")); System.out.println(result); }
測試結果:
[Student(name=九天, sex=男, salary=5000, age=18, star=天秤座)]
但是現在又會有人會問這個問題,我的那個方法中是這樣子的
filterStudent(List<Student> students, FilterProcess<Student> mp)
為什麼我的程式碼引數卻是這樣子的呢
filterStudent(list,(e)->e.getStar().equals("天秤座")
其實 -> 這個是一個連線符,左邊代表引數,而右邊代表函式體(也就是我們說的條件),這個e就是代表 FilterProcess<Student> mp 這個引數的,只不過我們得java8 中lambda可以給這個引數附加上了條件,這些條件篩選都是封裝到jdk8中內部類中自己實現的,所以我們只要附加條件就可以了,那個(e)就代表傳了引數。
1.4、真正運用lambda方法
@Test public void test1() { List<Student> list = Arrays.asList( new Student("九天","男",5000,18,"天秤座"), new Student("十夜","男",4000,16,"雙魚座"), new Student("十一郎","男",3000,24,"水瓶座") ); list.stream().filter((e) -> e.getStar().equals("天秤座")) .forEach(System.out::println); }
結果依然是相同的答案,直到第4個方法出來,對比前三個方法,簡單了很多,這就是我們lambda演練的過程。
總結:lambda主要是針對集合中條件的篩選,包括陣列等等。接下來我們介紹Stream API ,這個和Lambda息息相關,論重要性,lambda只是基礎,Stream API 才是真正的升級版
2、StreamAPI詳解
2.0、功能
父類:BasicStream
子類:Stream、IntStream、LongStream、DoubleStream
包含兩個型別,中間操作(intermediate operations)和結束操作(terminal operations)
下面是所有方法的屬於那一端操作的方法:
然後準備一個測試類,和一個靜態變數,圖下:
public class JdkTest { public static List<Student> list = Arrays.asList( new Student("九天", "男", 5000, 18, "天秤座"), new Student("十夜", "男", 4000, 16, "雙魚座"), new Student("十一郎", "男", 3000, 24, "水瓶座") ); }
接下來我們一個一個方法解析他們的作用
2.1、stream
將集合轉換成流,一般會使用流繼續後續操作。
@Test public void test0() { list.stream(); }
2.2、forEach遍歷
forEach遍歷集合,System.out::println等同於System.out.println()
@Test public void test1() { list.forEach(System.out::println); }
結果為:
2.3、filter過濾
該方法中是一個篩選條件,等同於sql查詢的where後面的篩選。
@Test public void test2() { list.stream().filter((e) -> e.getStar().equals("天秤座")) .forEach(System.out::println); }
2.4、map轉換集合
將List<Student> 轉換為List<String>, collect是將結果轉換為List
@Test public void test3() { List<String> names = list.stream().map(Student::getName).collect(Collectors.toList()); names.stream().forEach(System.out::println); }
結果:
2.5、mapToInt轉換數值流
轉換數值流,等同mapToLong、mapToDouble,如下這個是取最大值
@Test public void test4() { IntStream intStream = list.stream().mapToInt(Student::getAge); Stream<Integer> integerStream = intStream.boxed(); Optional<Integer> max = integerStream.max(Integer::compareTo); System.out.println(max.get()); }
結果為:
24
2.6、flatMap合併成一個流
將流中的每一個元素 T 對映為一個流,再把每一個流連線成為一個流
@Test public void test5() { List<String> list2 = new ArrayList<>(); list2.add("aaa bbb ccc"); list2.add("ddd eee fff"); list2.add("ggg hhh iii"); list2 = list2.stream().map(s -> s.split(" ")).flatMap(Arrays::stream).collect(Collectors.toList()); System.out.println(list2); }
結果為:
[aaa, bbb, ccc, ddd, eee, fff, ggg, hhh, iii]
2.7、distinct去重
@Test public void test6() { List<String> list2 = new ArrayList<>(); list2.add("aaa bbb ccc"); list2.add("ddd eee fff"); list2.add("ggg hhh iii"); list2.add("ggg hhh iii"); list2.stream().distinct().forEach(System.out::println); }
結果:
aaa bbb ccc ddd eee fff ggg hhh iii
2.8、sorted排序
@Test public void test7() { //asc排序 list.stream().sorted(Comparator.comparingInt(Student::getAge)).forEach(System.out::println); System.out.println("------------------------------------------------------------------"); //desc排序 list.stream().sorted(Comparator.comparingInt(Student::getAge).reversed()).forEach(System.out::println); }
結果:
Student(name=十夜, sex=男, salary=4000, age=16, star=雙魚座) Student(name=九天, sex=男, salary=5000, age=18, star=天秤座) Student(name=十一郎, sex=男, salary=3000, age=24, star=水瓶座) ------------------------------------------------------------------ Student(name=十一郎, sex=男, salary=3000, age=24, star=水瓶座) Student(name=九天, sex=男, salary=5000, age=18, star=天秤座) Student(name=十夜, sex=男, salary=4000, age=16, star=雙魚座)
2.9、skip跳過前n個
@Test public void test8() { list.stream().skip(1).forEach(System.out::println); }
2.10、limit擷取前n個
@Test public void test10() { list.stream().limit(1).forEach(System.out::println); }
結果為:
Student(name=九天, sex=男, salary=5000, age=18, star=天秤座)
2.11、anyMatch
只要有其中任意一個符合條件
@Test public void test11() { boolean isHave = list.stream().anyMatch(student -> student.getAge() == 16); System.out.println(isHave); }
2.12、allMatch
全部符合
@Test public void test12() { boolean isHave = list.stream().allMatch(student -> student.getAge() == 16); System.out.println(isHave); }
2.13、noneMatch
是否滿足沒有符合的
@Test public void test13() { boolean isHave = list.stream().noneMatch(student -> student.getAge() == 16); System.out.println(isHave); }
2.14、findAny
找到其中一個元素 (使用 stream() 時找到的是第一個元素;使用 parallelStream() 並行時找到的是其中一個元素)
@Test public void test14() { Optional<Student> student = list.stream().findAny(); System.out.println(student.get()); }
2.15、findFirst
找到第一個元素
@Test public void test15() { Optional<Student> student = list.stream().findFirst(); System.out.println(student.get()); }
2.17、count計數
@Test public void test17() { long count = list.stream().count(); System.out.println(count); }
2.18、of
生成一個字串流
@Test public void test18() { Stream<String> stringStream = Stream.of("i","love","you"); }
2.19、empty
生成一個空流
@Test public void test19() { Stream<String> stringStream = Stream.empty(); }
2.20、iterate
@Test public void test20() { List<String> list = Arrays.asList("a", "b", "c", "c", "d", "f", "a"); Stream.iterate(0, i -> i + 1).limit(list.size()).forEach(i -> { System.out.println(String.valueOf(i) + list.get(i)); }); }
3、Date
3.1、JDK7 Date缺點
1、所有的日期類都是可變的,因此他們都不是執行緒安全的,這是Java日期類最大的問題之一 2、Java的日期/時間類的定義並不一致,在java.util和java.sql的包中都有日期類,此外用於格式化和解析的類在java.text包中定義 3、java.util.Date同時包含日期和時間,而java.sql.Date僅包含日期,將其納入java.sql包並不合理。另外這兩個類都有相同的名字,這本身就是一個非常糟糕的設計。對於時間、時間戳、格式化以及解析,並沒有一些明確定義的類。對於格式化和解析的需求,我們有java.text.DateFormat抽象類,但通常情況下,SimpleDateFormat類被用於此類需求 4、日期類並不提供國際化,沒有時區支援,因此Java引入了java.util.Calendar和java.util.TimeZone類,但他們同樣存在上述所有的問題
3.2、JDK8 Date優勢
1、不變性:新的日期/時間API中,所有的類都是不可變的,這對多執行緒環境有好處。 2、關注點分離:新的API將人可讀的日期時間和機器時間(unix timestamp)明確分離,它為日期(Date)、時間(Time)、日期時間(DateTime)、時間戳(unix timestamp)以及時區定義了不同的類。 3、清晰:在所有的類中,方法都被明確定義用以完成相同的行為。舉個例子,要拿到當前例項我們可以使用now()方法,在所有的類中都定義了format()和parse()方法,而不是像以前那樣專門有一個獨立的類。為了更好的處理問題,所有的類都使用了工廠模式和策略模式,一旦你使用了其中某個類的方法,與其他類協同工作並不困難。 4、實用操作:所有新的日期/時間API類都實現了一系列方法用以完成通用的任務,如:加、減、格式化、解析、從日期/時間中提取單獨部分,等等。 5、可擴充套件性:新的日期/時間API是工作在ISO-8601日曆系統上的,但我們也可以將其應用在非IOS的日曆上。
3.3、JDK8 Date新增欄位
Java.time包中的是類是不可變且執行緒安全的。新的時間及日期API位於java.time中,java8 time包下關鍵欄位解讀。
屬性 | 含義 |
Instant | 代表的是時間戳 |
LocalDate | 代表日期,比如2020-01-14 |
LocalTime | 代表時刻,比如12:59:59 |
LocalDateTime | 代表具體時間 2020-01-12 12:22:26 |
ZonedDateTime | 代表一個包含時區的完整的日期時間,偏移量是以UTC/ 格林威治時間為基準的 |
Period | 代表時間段 |
ZoneOffset | 代表時區偏移量,比如:+8:00 |
Clock | 代表時鐘,比如獲取目前美國紐約的時間 |
3.4、獲取當前時間
Instant instant = Instant.now(); //獲取當前時間戳 LocalDate localDate = LocalDate.now(); //獲取當前日期 LocalTime localTime = LocalTime.now(); //獲取當前時刻 LocalDateTime localDateTime = LocalDateTime.now(); //獲取當前具體時間 ZonedDateTime zonedDateTime = ZonedDateTime.now(); //獲取帶有時區的時間
3.5、字串轉換
jdk8: String str = "2019-01-11"; DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); LocalDate localDate = LocalDate.parse(str, formatter); jdk7: SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); try { Date date = simpleDateFormat.parse(str); } catch (ParseException e){ e.printStackTrace(); }
3.6、Date轉換LocalDate
import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; import java.util.Date; public class Test { public static void main(String[] args) { Date date = new Date(); Instant instant = date.toInstant(); ZoneId zoneId = ZoneId.systemDefault(); // atZone()方法返回在指定時區從此Instant生成的ZonedDateTime。 LocalDate localDate = instant.atZone(zoneId).toLocalDate(); System.out.println("Date = " + date); System.out.println("LocalDate = " + localDate); } }
3.7、LocalDate轉Date
import java.time.LocalDate; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Date; public class Test { public static void main(String[] args) { ZoneId zoneId = ZoneId.systemDefault(); LocalDate localDate = LocalDate.now(); ZonedDateTime zdt = localDate.atStartOfDay(zoneId); Date date = Date.from(zdt.toInstant()); System.out.println("LocalDate = " + localDate); System.out.println("Date = " + date); } }
3.8、時間戳轉LocalDateTime
long timestamp = System.currentTimeMillis(); Instant instant = Instant.ofEpochMilli(timestamp); LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
3.9、LocalDateTime轉時間戳
LocalDateTime dateTime = LocalDateTime.now(); dateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli(); dateTime.toInstant(ZoneOffset.of("+08:00")).toEpochMilli(); dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
3.10、LocalDate方法總結
getYear() int 獲取當前日期的年份 getMonth() Month 獲取當前日期的月份物件 getMonthValue() int 獲取當前日期是第幾月 getDayOfWeek() DayOfWeek 表示該物件表示的日期是星期幾 getDayOfMonth() int 表示該物件表示的日期是這個月第幾天 getDayOfYear() int 表示該物件表示的日期是今年第幾天 withYear(int year) LocalDate 修改當前物件的年份 withMonth(int month) LocalDate 修改當前物件的月份 withDayOfMonth(intdayOfMonth) LocalDate 修改當前物件在當月的日期 isLeapYear() boolean 是否是閏年 lengthOfMonth() int 這個月有多少天 lengthOfYear() int 該物件表示的年份有多少天(365或者366) plusYears(longyearsToAdd) LocalDate 當前物件增加指定的年份數 plusMonths(longmonthsToAdd) LocalDate 當前物件增加指定的月份數 plusWeeks(longweeksToAdd) LocalDate 當前物件增加指定的週數 plusDays(longdaysToAdd) LocalDate 當前物件增加指定的天數 minusYears(longyearsToSubtract) LocalDate 當前物件減去指定的年數 minusMonths(longmonthsToSubtract) LocalDate 當前物件減去註定的月數 minusWeeks(longweeksToSubtract) LocalDate 當前物件減去指定的週數 minusDays(longdaysToSubtract) LocalDate 當前物件減去指定的天數 compareTo(ChronoLocalDateother) int 比較當前物件和other物件在時間上的大小,返回值如果為正,則當前物件時間較晚, isBefore(ChronoLocalDateother) boolean 比較當前物件日期是否在other物件日期之前 isAfter(ChronoLocalDateother) boolean 比較當前物件日期是否在other物件日期之後 isEqual(ChronoLocalDateother) boolean 比較兩個日期物件是否相等
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/9399028/viewspace-2674077/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- JDK8新特性詳解(一)JDK
- JDK8新特性詳解(二)JDK
- JDK8新特性JDK
- JDK8新特性-你瞭解多少JDK
- JDK8的新特性JDK
- JDK8新特性之stream()JDK
- JDK8新特性(4)—— stream 流JDK
- JDK8新特性之Stream流JDK
- JDK8新特性學習總結JDK
- JDK8 新特性學習筆記JDK筆記
- MySQL 5.5新特性詳解MySql
- MySQL 5.7 新特性詳解MySql
- JDK8新特性之函式式介面JDK函式
- JDK9新特性詳解JDK
- JDK10新特性詳解JDK
- JDK11新特性詳解JDK
- JDK12新特性詳解JDK
- JDK13新特性詳解JDK
- Java8 新特性詳解Java
- 詳解C#7.0新特性C#
- Android Studio 新特性詳解Android
- ES6新特性Promise詳解Promise
- Php5.5新特性 Generators詳解PHP
- 收藏版:《JDK13新特性詳解》JDK
- Oracle 18c新特性詳解 - 表和表空間相關的新特性Oracle
- JDK8特性之LocalDateTimeJDKLDA
- java JDK1.7版本新特性詳解JavaJDK
- 最權威的 Android Oreo 新特性詳解Android
- Oracle Database 12.2新特性詳解 --該國強OracleDatabase
- JDK8到JDK17有哪些吸引人的新特性?JDK
- Dubbo3詳解(5大新特性及功能圖解)圖解
- Oracle 18c新特性詳解:In-Memory 專題Oracle
- JDK8到底有啥特性JDK
- Swift 5新特性詳解:ABI 穩定終於來了!Swift
- Oracle 18c新特性詳解-多租戶專題Oracle
- 全面煥新|詳解 Grafana v9.0.x 新增功能特性Grafana
- Win10 Build 17692釋出 7個新特性詳解Win10UI
- C#–特性詳解C#