java8新特性

java8新特性

Lambda(核心)

用于快速的實(shí)現(xiàn)匿名內(nèi)部類中的方法。

例子:
Runnable r = new Runnable() {
    @Override
    public void run() {
        System.out.println("do something.");      
    }
}

如果我們想要寫一些線程,而每個(gè)線程中的實(shí)現(xiàn)很簡(jiǎn)單,就像例子中的只在控制臺(tái)打印一句話,那么還需要多寫4行代碼,很麻煩,可讀性也不高。下面,看下lambda的實(shí)現(xiàn):

Runnable r = () -> System.out.println("do something.");
lambda的基礎(chǔ)語法:
expression = (variable) -> action
  • variable:可以是一個(gè)變量,一個(gè)占位符,也可以是多個(gè)變量(x,y,z)。

  • action:實(shí)現(xiàn)的代碼邏輯,如果一行處理不完,可以用“{}”將執(zhí)行的代碼包起來。

  • expression:返回的值。

使用姿勢(shì):
public class FunctionInterfaceDemo {
    @FunctionalInterface
    interface Predicate<T> {
        boolean test(T t);
    }
    /**
     * 執(zhí)行Predicate判斷
     *
     * @param age       年齡
     * @param predicate Predicate函數(shù)式接口
     * @return          返回布爾類型結(jié)果
     */
    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);
    }
}

如上述代碼所示,當(dāng)一個(gè)接口類中只有一個(gè)方法,且接口類作為變量傳入函數(shù)中的時(shí)候,就可以使用lambda函數(shù)。

四大內(nèi)置接口

java8為lambda提供了4大內(nèi)置接口,分別消費(fèi)型接口、供給型接口、函數(shù)型接口、斷言型接口。其它的很多接口都是這四種接口衍生出來的,我們可以根據(jù)入?yún)⒑统鰠㈩愋偷牟煌`活使用。

消費(fèi)型接口示例(只有入?yún)?:

//消費(fèi)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捐贈(zèng)了"+money+"元")) ;
}

供給型接口示例(只有出參):

//傳入隨機(jī)數(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)⒊鰠⒍加?:

//轉(zhuǎ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類型):

//篩選出只有兩個(gè)字的水果
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);
處理過程
  1. 獲取流。
  2. 中間操作。
  3. 終止操作。

常見的流處理函數(shù)

/**
 * Stream的中間操作:
     * filter:排除元素
     * distinct:去重
     * limit:給定數(shù)量
     * skip:跳過幾個(gè)數(shù)量
     * map:實(shí)現(xiàn)函數(shù)
     * flatMap:扁平化
     * sorted:排序
 * Stream的終止操作:
     * allMatch,anyMatch,noneMatch:是否匹配元素
     * findFirst,findAny:返回元素
     * count,max,min:計(jì)數(shù),最大,最小
     * forEach:迭代
     * reduce:歸約
 */
并行流

java7中的Fork/Join框架,會(huì)將一個(gè)大任務(wù)拆分成多個(gè)小任務(wù),并行的去執(zhí)行,然后將各個(gè)小任務(wù)執(zhí)行的結(jié)果進(jìn)行合并,最終返回結(jié)果。缺點(diǎn)是代碼太難寫,每實(shí)現(xiàn)一次要寫好多定制化的代碼。

java8中提供了并行流的方式,底層用的就是Fork/Join框架,但只需要一句代碼:

list.parallelStream()

與java7相比,人性化了很多。

總結(jié)
  1. stream流函數(shù)中需要傳入的參數(shù)都是java8內(nèi)置的lambda接口,因此,推薦在函數(shù)中直接寫lambda。
  2. stream形式適用于集合數(shù)據(jù)快速的查找過濾等操作,當(dāng)需要對(duì)集合中的數(shù)據(jù)進(jìn)行很多的業(yè)務(wù)邏輯處理的時(shí)候,建議使用增強(qiáng)for循環(huán)。主要原因是lamdba寫法不適合寫的過長(zhǎng),處理過多業(yè)務(wù)邏輯,不利于后期維護(hù)。
練習(xí)
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());
}

時(shí)間API

簡(jiǎn)介
  1. java8對(duì)時(shí)間的api做了整理,主要為下面這三個(gè)類:LocalDate, LocalTime, LocalDateTime。從類名就可以看出,一個(gè)是日期,一個(gè)是時(shí)間,一個(gè)是全有。
  2. 我們平時(shí)使用的時(shí)候,盡量使用LocalDateTime。
  3. 在java8之前,我們使用的時(shí)間戳日期轉(zhuǎn)換工具SimpleDateFormat是線程不安全的,在使用的時(shí)候沒法抽成一個(gè)靜態(tài)工具類,需要在每一個(gè)線程下重新new一個(gè)SimpleDateFormat。java8中提供的DateTimeFormatter則是線程安全的。
開發(fā)中常用例子

1--獲取當(dāng)前時(shí)間戳

@Test
public void test1() {
    //包含了日期和時(shí)間,可以轉(zhuǎn)成秒,毫秒
    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--時(shí)間戳與需要的日期格式相互轉(zhuǎn)換

/**
 * 2.1 時(shí)間戳轉(zhuǎn)成想要的日期格式
 */
@Test
public void test2() {
    String pattern = "yyyy-MM-dd HH:mm:ss";
    long time = Instant.now().toEpochMilli();
    //時(shí)間戳轉(zhuǎn)成日期
    //1. 時(shí)間戳轉(zhuǎn)成標(biāo)準(zhǔn)日期
    LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault());
    System.out.println(localDateTime);
    //2. 標(biāo)準(zhǔn)日期轉(zhuǎn)成我們需要的格式
    DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
    String format = df.format(localDateTime);
    System.out.println(format);
}

/**
 * 2.2 給定任意日期格式轉(zhuǎn)成時(shí)間戳
 */
@Test
public void test3() {
    String pattern = "yyyy-MM-dd HH:mm:ss";
    //1. 將日期格式轉(zhuǎn)成標(biāo)準(zhǔn)日期
    DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
    LocalDateTime localDateTime = LocalDateTime.parse("2018-12-17 10:00:00", df);
    System.out.println(localDateTime);
    //2. 轉(zhuǎn)換成時(shí)間戳
    long milli = localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    System.out.println(milli);

}

3--時(shí)間日期差計(jì)算

/**
 * 3.1 計(jì)算時(shí)間差
 */
@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 計(jì)算日期差
 */
@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);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • java8新特性 原創(chuàng)者:文思 一、特性簡(jiǎn)介 速度更快 代碼更少,增加了Lambda 強(qiáng)大的Stream API ...
    文思li閱讀 3,098評(píng)論 1 1
  • 一、重要數(shù)據(jù)結(jié)構(gòu)和JVM的改動(dòng) 1.HashMap的改動(dòng) HashMap維護(hù)了一個(gè)Entry數(shù)組,put(K ke...
    一只愛java的貓閱讀 884評(píng)論 0 0
  • 前言: 北京時(shí)間2018年9月26日,Oracle官方發(fā)布Java 11。既然版本都更新到11了,現(xiàn)在才來學(xué)8是不...
    貪挽懶月閱讀 1,067評(píng)論 0 16
  • 對(duì)于Java開發(fā)者來說,Java8的版本顯然是一個(gè)具有里程碑意義的版本,蘊(yùn)含了許多令人激動(dòng)的新特性,如果能利用好這...
    jackcooper閱讀 1,085評(píng)論 0 6
  • 對(duì)于Java開發(fā)者來說,Java8的版本顯然是一個(gè)具有里程碑意義的版本,蘊(yùn)含了許多令人激動(dòng)的新特性,如果能利用好這...
    huanfuan閱讀 622評(píng)論 0 9

友情鏈接更多精彩內(nèi)容