java8新特性
Lambda(核心)
用于快速的實現(xiàn)匿名內部類中的方法头谜。
例子:
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("do something.");
}
}
如果我們想要寫一些線程,而每個線程中的實現(xiàn)很簡單,就像例子中的只在控制臺打印一句話悴品,那么還需要多寫4行代碼,很麻煩简烘,可讀性也不高苔严。下面,看下lambda的實現(xiàn):
Runnable r = () -> System.out.println("do something.");
lambda的基礎語法:
expression = (variable) -> action
variable:可以是一個變量孤澎,一個占位符届氢,也可以是多個變量(x,y,z)。
action:實現(xiàn)的代碼邏輯覆旭,如果一行處理不完退子,可以用“{}”將執(zhí)行的代碼包起來岖妄。
expression:返回的值。
使用姿勢:
public class FunctionInterfaceDemo {
@FunctionalInterface
interface Predicate<T> {
boolean test(T t);
}
/**
* 執(zhí)行Predicate判斷
*
* @param age 年齡
* @param predicate Predicate函數(shù)式接口
* @return 返回布爾類型結果
*/
public static boolean doPredicate(int age, Predicate<Integer> predicate) {
return predicate.test(age);
}
public static void main(String[] args) {
boolean isAdult = doPredicate(20, x -> x >= 18);
System.out.println(isAdult);
}
}
如上述代碼所示寂祥,當一個接口類中只有一個方法荐虐,且接口類作為變量傳入函數(shù)中的時候,就可以使用lambda函數(shù)丸凭。
四大內置接口
java8為lambda提供了4大內置接口福扬,分別消費型接口、供給型接口惜犀、函數(shù)型接口铛碑、斷言型接口。其它的很多接口都是這四種接口衍生出來的虽界,我們可以根據(jù)入?yún)⒑统鰠㈩愋偷牟煌`活使用汽烦。
消費型接口示例(只有入?yún)?:
//消費money
public static void donation(Integer money, Consumer<Integer> consumer){
consumer.accept(money);
}
public static void main(String[] args) {
donation(1000, money -> System.out.println("好心的麥樂迪為Blade捐贈了"+money+"元")) ;
}
供給型接口示例(只有出參):
//傳入隨機數(shù),返回集合
public static List<Integer> supply(Integer num, Supplier<Integer> supplier){
List<Integer> resultList = new ArrayList<Integer>() ;
for(int x=0;x<num;x++)
resultList.add(supplier.get());
return resultList ;
}
public static void main(String[] args) {
List<Integer> list = supply(10,() -> (int)(Math.random()*100));
list.forEach(System.out::println);
}
函數(shù)型接口示例(入?yún)⒊鰠⒍加?:
//轉換字符串為Integer
public static Integer convert(String str, Function<String, Integer> function) {
return function.apply(str);
}
public static void main(String[] args) {
Integer value = convert("28", x -> Integer.parseInt(x));
}
斷言型接口示例(有入?yún)⑴遥鰠閎oolean類型):
//篩選出只有兩個字的水果
public static List<String> filter(List<String> fruit, Predicate<String> predicate){
List<String> f = new ArrayList<>();
for (String s : fruit) {
if(predicate.test(s)){
f.add(s);
}
}
return f;
}
public static void main(String[] args) {
List<String> fruit = Arrays.asList("香蕉", "哈密瓜", "榴蓮", "火龍果", "水蜜桃");
List<String> newFruit = filter(fruit, (f) -> f.length() == 2);
System.out.println(newFruit);
}
stream流
用于快速處理集合的數(shù)據(jù)(一般用于查找過濾)
創(chuàng)建流
我們常用的創(chuàng)建流的方式有兩種刹缝,一是集合創(chuàng)建流(最常用),二是數(shù)組創(chuàng)建流颈将,也有其它方式創(chuàng)建流梢夯,但是一般不用。
//1. 通過集合創(chuàng)建stream(推薦)
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//2. 通過Arrays中的靜態(tài)方法
Integer[] intArray = new Integer[10];
Stream<Integer> stream2 = Arrays.stream(intArray);
處理過程
- 獲取流晴圾。
- 中間操作颂砸。
- 終止操作。
常見的流處理函數(shù)
/**
* Stream的中間操作:
* filter:排除元素
* distinct:去重
* limit:給定數(shù)量
* skip:跳過幾個數(shù)量
* map:實現(xiàn)函數(shù)
* flatMap:扁平化
* sorted:排序
* Stream的終止操作:
* allMatch,anyMatch,noneMatch:是否匹配元素
* findFirst,findAny:返回元素
* count,max,min:計數(shù)死姚,最大人乓,最小
* forEach:迭代
* reduce:歸約
*/
并行流
java7中的Fork/Join框架,會將一個大任務拆分成多個小任務都毒,并行的去執(zhí)行色罚,然后將各個小任務執(zhí)行的結果進行合并,最終返回結果账劲。缺點是代碼太難寫戳护,每實現(xiàn)一次要寫好多定制化的代碼。
java8中提供了并行流的方式瀑焦,底層用的就是Fork/Join框架腌且,但只需要一句代碼:
list.parallelStream()
與java7相比,人性化了很多榛瓮。
總結
- stream流函數(shù)中需要傳入的參數(shù)都是java8內置的lambda接口铺董,因此,推薦在函數(shù)中直接寫lambda禀晓。
- stream形式適用于集合數(shù)據(jù)快速的查找過濾等操作精续,當需要對集合中的數(shù)據(jù)進行很多的業(yè)務邏輯處理的時候坝锰,建議使用增強for循環(huán)。主要原因是lamdba寫法不適合寫的過長驻右,處理過多業(yè)務邏輯什黑,不利于后期維護。
練習
List<Transaction> transactions = null;
@Before
public void before(){
//交易員
Trader raoul = new Trader("Raoul", "Cambridge");
Trader mario = new Trader("Mario", "Milan");
Trader alan = new Trader("Alan", "Cambridge");
Trader brian = new Trader("Brian", "Cambridge");
//交易
transactions = Arrays.asList(
new Transaction(brian, 2011, 300),
new Transaction(raoul, 2011, 1000),
new Transaction(raoul, 2011, 400),
new Transaction(mario, 2012, 710),
new Transaction(mario, 2012, 700),
new Transaction(alan, 2012, 950)
);
}
/**
* 1. 找出2011年發(fā)生的所有交易堪夭, 并按交易額排序(從低到高)
*/
@Test
public void test1() {
transactions.stream()
.filter((t) -> t.getYear() == 2011)
.sorted(Comparator.comparingInt(Transaction::getValue))
.forEach(System.out::println);
}
/**
* 2. 交易員都在哪些不同的城市工作過愕把?
*/
@Test
public void test2() {
transactions.stream()
.map((e) -> e.getTrader().getCity())
.distinct()
.forEach(System.out::println);
}
/**
* 3. 查找所有來自劍橋的交易員,并按姓名排序
*/
@Test
public void test3() {
transactions.stream()
.filter((e) -> e.getTrader().getCity().equals("Cambridge"))
.map((e) -> e.getTrader().getName())
.sorted(Comparator.naturalOrder())
.distinct()
.forEach(System.out::println);
}
/**
* 4. 返回所有交易員的姓名字符串森爽,按字母順序排序
*/
@Test
public void test4() {
transactions.stream()
.map((e) -> e.getTrader().getName())
.sorted(Comparator.naturalOrder())
.forEach(System.out::println);
}
/**
* 5. 有沒有交易員是在米蘭工作的
*/
@Test
public void test5() {
boolean b = transactions.stream()
.anyMatch((e) -> e.getTrader().getCity().equals("Milan"));
System.out.println(b);
}
/**
* 6. 打印生活在劍橋的交易員的所有交易額之和
*/
@Test
public void test6() {
Optional<Integer> optional = transactions.stream()
.filter((e) -> e.getTrader().getCity().equals("Cambridge"))
.map(Transaction::getValue)
.reduce(Integer::sum);
System.out.println(optional.get());
}
/**
* 7. 所有交易中恨豁,最高的交易額是多少
*/
@Test
public void test7() {
Optional<Integer> optional = transactions.stream()
.map(Transaction::getValue)
.max(Integer::compareTo);
System.out.println(optional.get());
}
/**
* 8. 找到交易額最小的交易
*/
@Test
public void test8() {
Optional<Transaction> optional = transactions.stream()
.min(Comparator.comparingInt(Transaction::getValue));
System.out.println(optional.get());
}
時間API
簡介
- java8對時間的api做了整理,主要為下面這三個類:LocalDate, LocalTime, LocalDateTime爬迟。從類名就可以看出橘蜜,一個是日期,一個是時間付呕,一個是全有计福。
- 我們平時使用的時候,盡量使用LocalDateTime徽职。
- 在java8之前象颖,我們使用的時間戳日期轉換工具SimpleDateFormat是線程不安全的,在使用的時候沒法抽成一個靜態(tài)工具類姆钉,需要在每一個線程下重新new一個SimpleDateFormat说订。java8中提供的DateTimeFormatter則是線程安全的。
開發(fā)中常用例子
1--獲取當前時間戳
@Test
public void test1() {
//包含了日期和時間潮瓶,可以轉成秒陶冷,毫秒
Instant timestamp = Instant.now();
System.out.println(timestamp);
//毫秒
long milli = timestamp.toEpochMilli();
System.out.println(milli);
long second = timestamp.getEpochSecond();
System.out.println(second);
}
2--時間戳與需要的日期格式相互轉換
/**
* 2.1 時間戳轉成想要的日期格式
*/
@Test
public void test2() {
String pattern = "yyyy-MM-dd HH:mm:ss";
long time = Instant.now().toEpochMilli();
//時間戳轉成日期
//1. 時間戳轉成標準日期
LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault());
System.out.println(localDateTime);
//2. 標準日期轉成我們需要的格式
DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
String format = df.format(localDateTime);
System.out.println(format);
}
/**
* 2.2 給定任意日期格式轉成時間戳
*/
@Test
public void test3() {
String pattern = "yyyy-MM-dd HH:mm:ss";
//1. 將日期格式轉成標準日期
DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
LocalDateTime localDateTime = LocalDateTime.parse("2018-12-17 10:00:00", df);
System.out.println(localDateTime);
//2. 轉換成時間戳
long milli = localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
System.out.println(milli);
}
3--時間日期差計算
/**
* 3.1 計算時間差
*/
@Test
public void test4() throws InterruptedException {
Instant ins1 = Instant.now();
System.out.println(ins1.toEpochMilli());
Thread.sleep(1000);
Instant ins2 = Instant.now();
System.out.println(ins2.toEpochMilli());
long milli = Duration.between(ins1, ins2).toMillis();
System.out.println(milli);
}
/**
* 3.2 計算日期差
*/
@Test
public void test5() {
LocalDate now = LocalDate.now();
System.out.println(now);
LocalDate birth = LocalDate.of(1994, 11,26);
System.out.println(birth);
//相隔日期
Period period = Period.between(birth, now);
System.out.println(period.getYears() + "-" + period.getMonths() + "-" + period.getDays());
//相隔多少天
long dayDiff = ChronoUnit.DAYS.between(birth, now);
System.out.println(dayDiff);
}
4--日期加減
@Test
public void test6() {
LocalDateTime today = LocalDateTime.now();
LocalDateTime tor = today.plusDays(1);
LocalDateTime yes = today.minusDays(1);
System.out.println(yes);
System.out.println(today);
System.out.println(tor);
}