1.lambda表達式
? ? ? ? ? Lambda 允許把函數(shù)作為參數(shù)傳遞進方法中
? ? ? ? ? // 類型聲明 MathOperation addition = (int a, int b) -> a + b;?
? ? ? ? ? // 不用類型聲明 MathOperation subtraction = (a, b) -> a - b;
? ? ? ? ? // 大括號中的返回語句 MathOperation multiplication = (int a, int b) -> { return a * b; };
? ? ? ? ? Lambda 表達式只能引用標記了 final 的外層局部變量,lambda 表達式的局部變量可以不用聲明為 final,但是必須不可被后面的代碼修改
? ? 2.方法引用
? ? ? ? 構(gòu)造器引用:它的語法是Class::new,或者更一般的Class< T >::new
? ? ? ? public static Car create(final Supplier<Car> supplier) { return supplier.get(); }
? ? ? ? final Car car = Car.create( Car::new );
? ? ? ? 靜態(tài)方法引用:它的語法是Class::static_method
? ? ? ? public static void collide(final Car car) { System.out.println("Collided " + car.toString()); }
? ? ? ? cars.forEach( Car::collide );
? ? ? ? 特定類的任意對象的方法引用:它的語法是Class::method
? ? ? ? public void repair() { System.out.println("Repaired " + this.toString()); }
? ? ? ? cars.forEach( Car::repair );
? ? ? 特定對象的方法引用:它的語法是instance::method
? ? ? public void follow(final Car another) { System.out.println("Following the " + another.toString()); }
? ? ? final Car police = Car.create( Car::new );
? ? ? cars.forEach( police::follow );
? ? 3.Stream
? ? ? ? Stream(流)是一個來自數(shù)據(jù)源的元素隊列并支持聚合操作
? ? ? ? 數(shù)據(jù)源?流的來源。 可以是集合,數(shù)組,I/O channel, 產(chǎn)生器generator 等。
? ? ? ? 聚合操作?類似SQL語句一樣的操作, 比如filter, map, reduce, find, match, sorted等。
? ? ? ? forEach? ? limit? ? sorted?
? ? ? ? Random random = new Random();
? ? ? ? random.ints().limit(10).sorted().forEach(System.out::println);
? ? ? ? map
? ? ? ? List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
? ? ? ? // 獲取對應(yīng)的平方數(shù)
? ? ? ? List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
? ? ? ? filter
? ? ? ? List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
? ? ? ? // 獲取空字符串的數(shù)量
? ? ? ? long count = strings.stream().filter(string -> string.isEmpty()).count();
? ? ? ? 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);
(1)Stream創(chuàng)建
1) 通過參數(shù)序列創(chuàng)建Stream
// 利用可變參數(shù)直接構(gòu)造Stream,相比Arrays.stream()更簡單
// 下面語句創(chuàng)建的流內(nèi)容:10,20,30,40,50
final IntStream stream = IntStream.of(10, 20, 30, 40, 50);
// 下面語句創(chuàng)建的流內(nèi)容:red,blue,green
final Stream<String> colorStream = Stream.of("red", "blue", "green");
2) 通過數(shù)組創(chuàng)建Stream
相比Stream.of(),不用區(qū)分基礎(chǔ)數(shù)據(jù)類型,但參數(shù)只能是數(shù)組,不支持參數(shù)序列創(chuàng)建
final Integer[] numbers = {10, 20, 30, 40, 50, 60};
final Stream<Integer> numberStream = Arrays.stream(numbers);
final int[] intNumbers = {10, 20, 30, 40, 50, 60};
final IntStream result = Arrays.stream(intNumbers);
3) 通過集合創(chuàng)建Stream
final Collection<Integer> collection = Lists.newArrayList(10, 20, 30, 40, 50, 60);
final Stream<Integer> numberStream = collection.stream();
4) 通過集合創(chuàng)建并行Stream
final Collection<Integer> numbers = Lists.newArrayList(10, 20, 30, 40, 50, 60);
// 直接創(chuàng)建并行流
Stream<Integer> numberStream = numbers.parallelStream();
// 將串行流轉(zhuǎn)換為并行流
numberStream = numbers.stream().parallel();
5) 通過IO方式創(chuàng)建Stream
// 讀取文件的內(nèi)容,生成stream流
final Stream<String> stream = Files.lines(Paths.get("data.txt"), Charsets.UTF_8);
// 獲取目錄下的文件列表信息
final Stream<Path> listFile = Files.list(Paths.get("/"));
6) 通過生成器創(chuàng)建Stream
SecureRandom random = SecureRandom.getInstanceStrong();
// 直接傳入instance::method
// 下面語句創(chuàng)建的result包含10個隨機數(shù)
Stream<Integer> result = Stream.generate(random::nextInt).limit(10);
// 直接傳入lambda表達式
// 下面語句創(chuàng)建的result包含10個元素,每個值由根據(jù)當(dāng)前時間 % 100計算得來
// 以某次執(zhí)行為例,result包含36,3,40,71,46,43,68,97,38,92
result = Stream.generate(() -> (int) (System.nanoTime() % 100)).limit(10);
7) 通過iterate創(chuàng)建Stream
// 以0為種子,f(n) = n + 3, f(f(n)) ...
// 下面語句創(chuàng)建的Stream內(nèi)容:0 3 6 9 12 15 18 21 24 27
Stream.iterate(0, n -> n + 3).limit(10).forEach(Stubs::doWhatever);
8) 通過區(qū)間創(chuàng)建整數(shù)序列Stream
// 通過range、rangeClosed生成序列,該序列為數(shù)學(xué)中的區(qū)間序列。
// 生成[-100, 100)區(qū)間的元素序列,不包括end元素100
final IntStream range = IntStream.range(-100, 100);
// 由于start > end,不符合區(qū)間定義,返回空區(qū)間,Stream中元素長度為0
final IntStream emptyRange = IntStream.range(100, -100);
// 生成[-100,100]區(qū)間的元素序列,包含end元素100
final IntStream rangeClosed = IntStream.rangeClosed(-100, 100);
// LongStream range生成
// 生成[-100, 100)區(qū)間的元素序列,不包括end元素100
final LongStream longRange = LongStream.range(-100L, 100L);
// 生成[-100,100]區(qū)間的元素序列,包含end元素100
final LongStream longRangeClosed = LongStream.rangeClosed(-100L, 100L);
(1)Stream基礎(chǔ)操作
1) 計算Stream大小
// 計算Stream中元素的格式,count為特殊的reduce操作,對于sum(), max(), min(), average(),count()等操作不建議直接使用reduce()
// 等同于stream.mapToLong(e -> 1L).sum();
long count = Stream.of().count(); // count = 0
count = Stream.of(10).count(); // count = 1
count = Stream.of(10, 20, 30, 40, 50).count(); // count = 5
1) Stream轉(zhuǎn)換為字符串
final Stream<String> stream = Stream.of("red", "blue", "green");
// 執(zhí)行結(jié)果:colors值為red|blue|green
String colors = stream.collect(Collectors.joining("|"));
2) Stream轉(zhuǎn)換為數(shù)組
final Stream<String> stream = Stream.of("red", "blue", "green");
// 執(zhí)行結(jié)果:colors數(shù)組為[red, blue, green]
String[] colors = stream.toArray(String[]::new);
3) Stream轉(zhuǎn)換為ArrayList
final Stream<String> stream = Stream.of("red", "blue", "green");
// colors類型為ArrayList,結(jié)果為[red, blue, green]
List<String> colors = stream.collect(Collectors.toList());
4) Stream轉(zhuǎn)換為List
不同業(yè)務(wù)場景對性能、內(nèi)存占用等有不同的訴求。對于ArrayList不滿足的場景,可將Stream元素收集到指定類型的List,如:LinkedList。
final Stream<String> stream = Stream.of("red", "blue", "green");
// Stream轉(zhuǎn)換的List類型為LinkedList
// 執(zhí)行結(jié)果:colors結(jié)果為[red, blue, green]
List<String> colors = stream.collect(Collectors.toCollection(LinkedList::new));
5) Stream轉(zhuǎn)換為指定類型Collection
final Stream<String> stream = Stream.of("red", "blue", "green");
// colors為LinkedHashSet,對于其他的類型在toCollection()方法參數(shù)中指定
Set<String> colors = stream.collect(Collectors.toCollection(LinkedHashSet::new));
6) Stream轉(zhuǎn)換為Set
final Stream<String> stream = Stream.of("red", "blue", "green");
// 默認轉(zhuǎn)換為HashSet
// 執(zhí)行結(jié)果:colors值為[red, green, blue]
final Set<String> colors = stream.collect(Collectors.toSet());
7) Stream轉(zhuǎn)換為Map
Collectors.toMap()需要保證Key唯一性,如果不唯一,則需給出合并策略
Collectors.toMap()需要保證Stream元素為NonNull,且映射到Map的value值必須為NonNull
final Stream<User> stream = Stream.of(new User("1", "Jerry", "Male"), new User("2", "Kitty", "Female"));
// 以User的ID作為key,User實例作為value,轉(zhuǎn)換過程默認使用的是HashMap
// user.getId()必須是唯一的,否則會拋出java.lang.IllegalStateException: Duplicate key
// 執(zhí)行結(jié)果:map值為
// {1=User(id=1, username=Jerry, salary=0, gender=Male), 2=User(id=2, username=Kitty, salary=0, gender=Female)}
Map<String, User> map = stream.collect(Collectors.toMap(User::getId, Function.identity()));
final Stream<User> stream2 = Stream.of(new User("1", "Jerry", "Male"), new User("2", "Kitty", "Female"));
// 將User的ID作為key,username作為value
// 執(zhí)行結(jié)果:mapIdName值為{1=Jerry, 2=Kitty}
Map<String, String> mapIdName = stream2.collect(Collectors.toMap(User::getId, User::getUsername));
如果Collectors.toMap() key值不唯一,給出合并策略
final Stream<User> duplicateKeyStream =
? ? Stream.of(new User("1", "Jerry", "Male"), new User("20", "Jerry", "Female"));
// 下面以username作為key,Stream中存在同名的username "Jerry"。
// 以“后者覆蓋前者”的策略解決沖突
// 執(zhí)行結(jié)果:map值為{Jerry=User(id=20, username=Jerry, salary=0, gender=Female)}
Map<String, User> map =
? ? duplicateKeyStream.collect(Collectors.toMap(User::getUsername, Function.identity(), (key1, key2) -> key2));
如果Stream存在null元素,Collectors.toMap()轉(zhuǎn)換失敗,建議通過filter()過濾后再進行轉(zhuǎn)換
final Stream<User> nullElementStream = Stream.of(new User("1", "Jerry", "Male"), null);
// 下面代碼Stream中存在null元素,Collectors.toMap()將拋出NullPointerException異常
Map<String, String> mapIdName = nullElementStream.collect(Collectors.toMap(User::getId, User::getUsername));
// 過濾出NonNull的元素后進行Map轉(zhuǎn)換,轉(zhuǎn)換后的結(jié)果為{1=Jerry}
nullElementStream.filter(Objects::nonNull).collect(Collectors.toMap(User::getId, User::getUsername));
如果Map的value值為null,Collectors.toMap()轉(zhuǎn)換失敗,建議通過filter()過濾后再進行轉(zhuǎn)換
final Stream<User> nullValueStream = Stream.of(new User("1", "Jerry", "Male"), new User("2", null));
// 將id、username信息轉(zhuǎn)換為map,由于存在username為null,Collectors.toMap()將拋出NullPointerException異常
Map<String, String> mapIdName = nullValueStream.collect(Collectors.toMap(User::getId, User::getUsername));
// 過濾出Map的value為NonNull的元素后進行Map轉(zhuǎn)換,轉(zhuǎn)換后的結(jié)果為{1=Jerry}
nullValueStream.filter(p -> p != null && StringUtils.isNotEmpty(p.getUsername()))
? ? .collect(Collectors.toMap(User::getId, User::getUsername));
8) Stream轉(zhuǎn)換為分組Map
final Stream<User> stream = Stream.of(new User("1", "Jerry", "Male"), new User("2", "Kitty", "Female"));
// 按性別分組,分組結(jié)果為
// {Female=[User(id=2, username=Kitty, salary=0, gender=Female)], Male=[User(id=1, username=Jerry, salary=0,
// gender=Male)]}
Map<String, List<User>> group = stream.collect(Collectors.groupingBy(User::getGender));
// Stream實例執(zhí)行一次終端操作后將不能再次使用,因此,此處創(chuàng)建新的Stream
final Stream<User> stream2 = Stream.of(new User("1", "Jerry", "Male"), new User("2", "Kitty", "Female"));
// 按是否為Female分組,分組結(jié)果為
// {false=[User(id=1, username=Jerry, salary=0, gender=Male)], true=[User(id=2, username=Kitty, salary=0,
// gender=Female)]}
Map<Boolean, List<User>> group2 =
? ? stream2.collect(Collectors.partitioningBy(p -> "Female".equalsIgnoreCase(p.getGender())));
? ? 4.日期時間 API
? ? ? ? java.time包涵蓋了所有處理日期,時間,日期/時間,時區(qū),時刻(instants),過程(during)與時鐘(clock)的操作
? ? ? ? import java.time.LocalDate;
? ? ? ? import java.time.LocalTime;
? ? ? ? import java.time.LocalDateTime;
? ? ? ? import java.time.Month;