主頁 > 後端開發 > Java8新特性學習

Java8新特性學習

2021-05-05 15:36:21 後端開發

學習代碼

1.主要內容

1.Lambda運算式
2. 函式式介面
3. 方法參考于構造器參考
4. Stream API
5. 介面中的默認方法與靜態方法
6. 新時間日期API
7. 重復注解

入門案例:根據條件獲取員工資訊

//員工表
public class Employee {
    private String name;
    private int age;
    private double salary;
    ....
}
//員工資訊
List<Employee> emplpyees = Arrays.asList(
    new Employee("張三", 14, 5444.42),
    new Employee("李四", 39, 3434.15),
    new Employee("王五", 31, 5425.55),
    new Employee("趙六", 11, 2544.42), 
    new Employee("陳七", 98, 944.42));
1.傳統方式
    @Test
    public void test3() {
        List<Employee> emps = filterEmployees(emplpyees);
        System.out.println(emps);
    }
    // 獲取當前員工中年齡大于35的員工
    public List<Employee> filterEmployees(List<Employee> list) {
        List<Employee> emps = new ArrayList<>();
        for (Employee emp : list) {
            if (emp.getAge() >= 35) {
                emps.add(emp);
            }
        }
        return emps;
    }

如果條件改變呢?比如,改成想要工資大于5000的員工資訊.傳統方式,拷貝代碼,修改if代碼
優化方式一:設計模式,策略設計模式
定義一個借口,根據條件創建實作類

//定義一個介面
public interface MyProdicate<T> {
    public boolean test(T t);
}
//實作類,
public class FilterEmployeeByAge implements MyProdicate<Employee>{
    @Override
    public boolean test(Employee t) {
        return t.getAge()>=35;
    }
}
//判斷
public List<Employee> filterEmployees(List<Employee> list, MyProdicate<Employee> mp) {
        List<Employee> emps = new ArrayList<>();
        for (Employee emp : list) {
            if (mp.test(emp)) {
                emps.add(emp);
            }
        }
        return emps;
}
//測驗
@Test
    public void test4() {
        List<Employee> emps = filterEmployees(emplpyees, new FilterEmployeeByAge());
        System.out.println(emps);
    }

不過,這種方式中,每加一個條件,就要加一個實作類,不好,在此基礎上進行優化
匿名內部類

// 優化方式二,匿名內部類
    public void test5() {
        List<Employee> emps = filterEmployees(emplpyees, new MyProdicate<Employee>() {
            @Override
            public boolean test(Employee t) {
                return t.getSalary() >= 5000;
            }
        });
        System.out.println(emps);
    }

匿名內部類每次使用,還是要寫多余代碼,可以繼續優化
lambda運算式

// 優化方式三:lambda]
    @Test
    public void test6() {
        List<Employee> emps = filterEmployees(emplpyees, (e) -> e.getSalary() < 5000);
        emps.forEach(System.out::println);
    }

如果沒有介面.怎么優化Stream API

// 優化方式四,只有emplpyees,Stream API
@Test
public void test7() {
    emplpyees.stream().filter((e) -> e.getSalary() < 5000).forEach(System.out::println);
}

2.Lambda運算式

1.匿名函式

Lambda是一個匿名函式,可以理解為一段可以傳遞的代碼(將代碼像資料一樣傳遞);
可以寫出更簡潔、更靈活的代碼;
作為一種更緊湊的代碼風格,是Java語言表達能力得到提升,

2.語法格式

1.lambda運算式的基礎語法

java8中引入新的運算子"->",箭頭運算子/lambda運算子 箭頭運算子將lambda 運算式拆分成兩部分:
左側:lambda的引數串列 右側:lambda中所需要執行的功能,即lambda體

? 語法格式1:無引數,無回傳值 :()->具體功能
? 語法格式2:有一個引數,無回傳值:(x)->具體功能
? 語法格式3:若只有一個引數,引數小括號可以省略不寫:x->具體功能
? 語法格式4:有兩個以上的引數,lambda體中有多條陳述句,有回傳值:
? 語法格式5:有兩個引數,lambda體只有一條陳述句,有回傳值,{}和return可以省略
? 語法格式6:lambda運算式的資料型別可以省略不寫,因為jvm的編譯器可以通過背景關系推斷出資料型別,即型別推斷
  口訣:
? 左右遇一括號省
? 左側推斷型別省
package cn.zj.lambda;
import java.util.Comparator;
import java.util.function.Consumer;
import org.junit.jupiter.api.Test;
/**
 * 1.lambda運算式的基礎語法,java8中引入新的運算子"->",箭頭運算子/lambda運算子 箭頭運算子將lambda 運算式拆分成兩部分:
 * 左側:lambda的引數串列 右側:lambda中所需要執行的功能,即lambda體
 *
 * 語法格式1:無引數,無回傳值 :()->具體功能
 * 語法格式2:有一個引數,無回傳值:(x)->具體功能
 * 語法格式3:若只有一個引數,引數小括號可以省略不寫:x->具體功能
 * 語法格式4:有兩個以上的引數,lambda體中有多條陳述句,有回傳值:
 * 語法格式5:有兩個引數,lambda體只有一條陳述句,有回傳值,{}和return可以省略
 * 語法格式6:lambda運算式的資料型別可以省略不寫,因為jvm的編譯器可以通過背景關系推斷出資料型別,即型別推斷
 * 
 * 口訣:
 * 左右遇一括號省
 * 左側推斷型別省
 * 
 */
public class TestLambda2 {
    // 1.無引數,無回傳值
    @Test
    public void test1() {
        int i = 1;// 在7之前,內部類呼叫同級別變數引數,需要加final修飾符,8以后不加,底層默認加了
        Runnable r = () -> System.out.println("hello Lambda" + i);
        r.run();
    }
    
    @Test
    public void test2() {
        Consumer<String> c=(x)->System.out.println(x);
        c.accept("lambda");
        
    }
    
    @Test
    public void test3() {
        Consumer<String> c=x->System.out.println(x);
        c.accept("lambda");
        
    }
    
    
    @Test
    public void test4() {
        Comparator<Integer> com=(x,y)->{
            System.out.println("lambda多條陳述句");
            return Integer.compare(x, y);
        };
        int compare = com.compare(11, 33);
        System.out.println(compare);
    }
    
    @Test
    public void test5() {
        Comparator<Integer> com=(x,y)->Integer.compare(x, y);
        int compare = com.compare(11, 33);
        System.out.println(compare);
    }
}

2.lambda運算式需要函式式介面的支持函式式介面

函式式介面:只有一個抽象方法的介面

public interface MyProdicate<T> {
    public boolean test(T t);
}

可以使用注解@FunctionalInterface修飾,檢查是否是函式式介面

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

3.練習

3.1.呼叫Collections.sort()方法,通過定制排序比較兩個Employee(先按年齡比,年齡相同按姓名比),使用lambda作為引數傳遞

  @Test
  public void test1() {
      Collections.sort(emps, (e1, e2) -> {
          if (e1.getAge() == e2.getAge()) {
              return e1.getName().compareTo(e2.getName());
          } else {
              return Integer.compare(e1.getAge(), e2.getAge());
          }
      });
      emps.forEach(System.out::println);
  }

3.2.①宣告函式式介面,介面中宣告抽象方法,public String getValue(String str);
②宣告類LambdaTest,類中撰寫方法使用介面作為引數,將一個字串轉為大寫并回傳
③再將字串的第2和第4個索引位置進行截取

@FunctionalInterface
public interface MyFunction {
 public String getValue(String str);
}
@Test
 public void test2() {
     String str = strHandler("hellolambda", (s) -> s.toUpperCase());
     str = strHandler(str, (s) -> s.substring(2, 5));
     System.out.println(str);
 }
 public String strHandler(String str, MyFunction mf) {
     return mf.getValue(str);
 }

3.3.①宣告一個帶兩個泛型的函式式介面,泛型型別為<T,R>,T為引數,R為回傳值,
②介面中宣告對應方法
③在LambdaTest類中宣告方法,使用介面作為引數,計算兩個long型引數的和
④再計算兩個long型引數的乘積

@FunctionalInterface
public interface MyFunction2<T,R> {
 public R getValue(T t1,T t2);
}
@Test
 public void test3() {
     Long l1=longHandler(4121754L,55524L,(x,y)->x+y);
     Long l2=longHandler(4121754L,55524L,(x,y)->x*y);
     System.out.println(l1);
     System.out.println(l2);
 }
 
 public Long longHandler(Long l1, long l2, MyFunction2<Long,Long> mf) {
     return  mf.getValue(l1, l2);
 }

3.java內置四大型別介面

函式式介面引數型別回傳型別用途
Consumer
消費型介面
Tvoid對型別為T的物件應用操作:void accept(T t)
Supplier
提供型介面
T回傳型別為T的物件:T get()
Function<T, R>
函式型介面
TR對型別為T的物件應用操作,并回傳結果為R型別的物件:R apply(T t)
Predicate
斷言型介面
Tboolean確定型別為T的物件是否滿足某約束,并回傳boolean值:boolean test(T t)

1.Consumer 消費型介面

//消費型介面Consumer
    @Test
    public void test1() {
        happy(10000,(m)->System.out.println("吃消費"+m));
    }
    
    public void happy(double money,Consumer<Double> con) {
        con.accept(money);
    }

2.Suppplier供給型介面 T get()

//供給型介面Supplier
    @Test
    public void test2() {
        List<Integer>  list=getNumList(10,()->(int)(Math.random()*100));
        System.out.println(list);
    }
    //產生一些整數,并放入集合中
    public List<Integer> getNumList(int num,Supplier<Integer> sup){
        List<Integer> list=new ArrayList<>();
        for(int i=0;i<num;i++) {
            list.add(sup.get());
        }
        return list;
    }

3.Function<T,R>函式型介面 R apply(T t)

//函式型介面Function
    @Test
    public void test3() {
        String str = strHandler(" 韓梅梅要嫁給王五了 ", (s)->s.trim());
        System.out.println(str);
    }
    //處理字串
    public String strHandler(String str,Function<String,String> fun) {
        return fun.apply(str);
    }

4.Predicate斷定型介面

   // 斷定型介面Predicate
    @Test
    public void test4() {
        List<String> list = Arrays.asList("hello","world","lambda","ok","good");
        List<String> strList = filterStr(list, (s)->s.length()>4);
        System.out.println(strList);
    }
    // 將滿足條件的字串加到集合中
    public List<String> filterStr(List<String> list, Predicate<String> pre) {
        List<String> strList = new ArrayList<>();
        for (String str : list) {
            if (pre.test(str))
                strList.add(str);
        }
        return strList;
    }

其它介面
在這里插入圖片描述

3.方法參考與構造器參考

1.方法參考

如果lambda體中的內容已經有方法實作了,可以使用"方法參考"(可以理解為lambda的另一種表現形式)

1.物件::實體方法名

//物件::實體方法名
@Test
public void test1() {
    Consumer<String> con=(x)->System.out.println(x);
    con.accept("哇咔咔");
    //方法參考:介面中抽象方法的引數和回傳值型別,需要與要參考的方法的引數和回傳值型別一樣
    PrintStream ps=System.out;
    Consumer<String> con1=ps::println;
    con1.accept("把金三角");
    Consumer<String> con2=System.out::println;
    con2.accept("asasa");
}

@Test
public void test2() {
    Employee emp=new Employee("張三", 11, 124.55);
    Supplier<String> sup=()->emp.getName();
    String str = sup.get();
    System.out.println(str);
    
    //方法參考
    Supplier<Integer> sup1=emp::getAge;
    Integer age = sup1.get();
    System.out.println(age);
}

2.類::靜態方法名

//類::靜態方法

 @Test
    public void test3() {
        Comparator<Integer> com=(x,y)->Integer.compare(x, y);
        
        Comparator<Integer> com1=Integer::compare;
        int compare = com1.compare(11, 12);
        System.out.println(compare);
    }

3.類::實體方法名

//類::實體方法名
    @Test
    public void test4() {
        BiPredicate<String, String>bp=(x,y)->x.equals(y);
        
        //注意,第一個引數是實體方法的呼叫者,第二個引數是實體方法的引數
        BiPredicate<String, String>bp1=String::equals;
        boolean test = bp1.test("ss", "ss");
        System.out.println(test);
    }

4.注意

注意:
lambda體中呼叫方法的引數串列與回傳值型別,要與函式式介面中抽象方法的引數串列和回傳值型別保持一致

lambda引數串列中的第一個引數是實體方法的引數者,第二個引數是實體方法的引數時可以使用類::實體方法名

2.構造器參考

格式:ClassName::new
//無參
    @Test
    public void test1() {
        Supplier<Employee> sup=()->new Employee();
        //構造器參考,無參
        Supplier<Employee> sup1=Employee::new;
        
    }
    //有引數
    @Test
    public void test2() {
        Function<Integer, Employee>fun=(x)->new Employee(x);
        
        Function<Integer, Employee>fun1=Employee::new;
        Employee emp = fun1.apply(11);
        System.out.println(emp);
        
        //兩個引數
        BiFunction<Integer,Integer, Employee>bf=Employee::new;
        Employee emp2 = bf.apply(11,21);
        System.out.println(emp2);
    }

注意:需要呼叫的構造器的引數串列要與函式式介面中抽象方法的引數串列保持一致

3.陣列參考

Type::new


    @Test
    public void test1() {
        Function<Integer, String[]> fun=(x)->new String[x];
        String[] strArr = fun.apply(12);
        System.out.println(strArr.length);
        
        Function<Integer, String[]> fun1=String[]::new;
        String[] strArr2 = fun1.apply(10);
        System.out.println(strArr2.length);
    }

4.Stream API

1.Stream 概念

是資料渠道,用于操作資料源(集合.陣列等)所生成的元素序列. “集合將的事資料,流講的是計算” 注意:
ⅰ. Stream自己不會存盤元素
ⅱ. Stream不會改變源物件.相反,他們會回傳一個持有結果的新Stream
ⅲ. Stream操作是延遲執行的.這意味著他們會等到需要結果的時候才執行

2.操作步驟

1.創建 Stream

一個資料源(集合,陣列等)獲取一個流

  1. 通過Collection系列集合提供的stream()或paralleStream()
  2. 通過Arrays中的靜態方法stream()獲取陣列流
  3. 通過Stream類中的靜態方法of()
  4. 創建無限流
// 創建Stream
  @Test
    public void test1() {
        // 1.通過Collection系列集合提供的stream()或paralleStream()
        List<String> list = new ArrayList<>();
        Stream<String> stream = list.stream();
        
        //2.通過Arrays中的靜態方法stream()獲取陣列流
        Employee[] emps=new Employee[10];
        Stream<Employee> stream2 = Arrays.stream(emps);
        
        //3.通過Stream類中的靜態方法of()
        Stream<String> stream3 = Stream.of("aa","bb","cc");
        
        //4.創建無限流
        //1)迭代
        Stream<Integer> stream4 = Stream.iterate(0, (x)->x+2);
        //stream4.limit(10).forEach(System.out::println);
        
        //2)生成
        Stream<Double> stream5 = Stream.generate(()->Math.random());
        //limit(10)中間操作
        //forEach 終止操作
        stream5.limit(10).forEach(System.out::println);//終止操作
    }

2.中間操作

一個中間操作鏈,對資料源的資料進行處理
多個中間操作可以連接起來形成一個流水線,除非流水線上出發終止操作,否則中間操作不會執行任何的處理.而在終止操作時一次性全部處理,稱為"惰性求值"

1.篩選與切片
方法描述
filter(Predicate p)接收Lambda,從流中排除某些元素
distinct()篩選,通過流所生成元素的hashCode()和equals()去除重復元素
limit(long maxSize)截斷流,使其元素不超過給定數量
skip(long n)跳過元素,回傳一個扔掉了前n個元素的流.若流中元素不足n個,則回傳一個空流.與limit(n)互補
public class TestStreamAPI02 {
    
    List<Employee> emps = Arrays.asList(
            new Employee("張三", 14, 5444.42),
            new Employee("李四", 39, 3434.15),
            new Employee("李四", 39, 3434.15),
            new Employee("王五", 31, 5425.55),
            new Employee("趙六", 31, 2544.42), 
            new Employee("陳七", 98, 944.42));
    //中間操作
    /*
     * 篩選與切片
     * filter-接受lambda,從流中排除某些元素
     * limit-截斷流,使其元素不能超過給定數量
     * skip(n) -跳過元素,回傳一個扔掉了前n個元素的流,若流中元素不足n個,則回傳一個空流.與limit(n)互補
     * distinct-篩選,通過流所生成元素的hashCode()和equals()去除重復元素
     * 
     */
    //distinct
    @Test
    public void test5() {
        emps.stream().filter((e)->e.getSalary()>3000).distinct().forEach(System.out::println);
    
    }
    
    //skip
    @Test
    public void test4() {
        emps.stream().filter((e)->e.getSalary()>5000).skip(1).forEach(System.out::println);
    
    }
    
    //limit,得到對應的資料后,會停止迭代,短路
    @Test
    public void test3() {
        emps.stream().filter((e)->e.getSalary()>5000).limit(2).forEach(System.out::println);
    }
    
    
    //內部迭代:迭代操作由Stream API完成
    //filter
    @Test
    public void test1() {
        //中間操作,不會執行任何操作
        Stream<Employee> stream = emps.stream().filter((e)->e.getAge()>35);
        //終止操作,一次性執行全部內容,"惰性求值"
        stream.forEach(System.out::println);
    }
    
    //外部迭代
    @Test
    public void test2() {
        Iterator<Employee> it = emps.iterator();
        while(it.hasNext()) {
            System.out.println(it.next());
        }
    }
    
}
2.映射

? map:接收 Lambda ,將元素轉換為其他形式或提取資訊;接受一個函式作為引數,該函式會被應用到每個元素上,并將其映射成一個新的元素
? flatMap:接收一個函式作為引數,將流中每一個值都換成另一個流,然后把所有流重新連接成一個流

public class TestStreamAPI3 {
    
    List<Employee> emps = Arrays.asList(
            new Employee("張三", 14, 5444.42),
            new Employee("李四", 39, 3434.15),
            new Employee("李四", 39, 3434.15),
            new Employee("王五", 31, 5425.55),
            new Employee("趙六", 31, 2544.42), 
            new Employee("陳七", 98, 944.42));
    //中間操作
    //映射
    //map-接收Lambda,將元素轉換成其它形式或提取資訊,接收一個函式作為引數,該函式會被應用到每個元素上,并將其映射成一個新的元素
    //flatMap-接收一個函式作為引數,將流中的每個值都換成另一個流,然后把所有流連接成一個流
    
    
    //flatMap
    @Test
    public void test2() {
        List<String> list=Arrays.asList("aaa","bbb","ccc","ddd","eee");
        list.stream().flatMap(TestStreamAPI3::filterCharacter).forEach(System.out::println);
    }
    
    public static Stream<Character> filterCharacter(String str){
        List<Character> list = new ArrayList<>();
        for (char c : str.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }
    
    //map
    @Test
    public void test1() {
        List<String> list=Arrays.asList("aaa","bbb","ccc","ddd","eee");
        list.stream().map((x)->x.toUpperCase()).forEach(System.out::println);
        System.out.println("-------------------------------");
        emps.stream().map((x)->x.getName()).forEach(System.out::println);
        System.out.println("-------------------------------");
        Stream<Stream<Character>> stream=list.stream().map(TestStreamAPI3::filterCharacter);
        stream.forEach((sm)->{
            sm.forEach(System.out::println);
        });
    }
    
    
}
3.排序

? sorted():自然排序
? sorted(Comparator c):定制排序

//中間操作
    //排序
    //sorted():自然排序
    //sorted(Comparator c):定制排序
    //sorted(Comparator c)
        @Test
        public void test2() {
            emps.stream().sorted((x,y)->{
                if(x.getAge()==y.getAge()) {
                    return x.getName().compareTo(y.getName());
                }else {
                    return Integer.compare(x.getAge(), y.getAge());
                }
            }).forEach(System.out::println);
        }
    
    //sorted
    @Test
    public void test1() {
        List<String> list=Arrays.asList("aaa","ddd","bbb","eee","ccc");
        list.stream().sorted().forEach(System.out::println);
    }

3.終止操作(終端操作)

一個終止操作,執行中間操作鏈,并產生結果

1.查找與匹配
? allMatch:檢查是否匹配所有元素
? anyMatch:檢查是否至少匹配一個元素
? noneMatch:檢查是否沒有匹配所有元素
? findFirst:回傳第一個元素
? findAny:回傳當前流中的任意元素
? count:回傳流中元素的總個數
? max:回傳流中最大值
? min:回傳流中最小值
public class TestStreamAPI4 {
    List<Employee> emps = Arrays.asList(
            new Employee(1,"張三", 14, 5444.42,Status.FREE),
            new Employee(2,"李四", 39, 3434.15,Status.BUSY),
            new Employee(3,"李四", 39, 3434.15,Status.VOCATION), 
            new Employee(4,"王五", 31, 5425.55,Status.FREE), 
            new Employee(5,"趙六", 31, 2544.42,Status.BUSY),
            new Employee(6,"陳七", 98, 944.42,Status.BUSY));
    // 終止操作
    // 查找與匹配
    // allMatch:檢查是否匹配所有元素
    // anyMatch:檢查是否至少匹配一個元素
    // noneMatch:檢查是否沒有匹配所有元素
    // findFirst:回傳第一個元素
    // findAny:回傳當前流中的任意元素
    // count:回傳流中元素的總個數
    // max:回傳流中最大值
    // min:回傳流中最小值
    
    //min
    @Test
    public void test8() {
        /*
         * Optional<Employee> op =
         * emps.stream().min((x,y)->Double.compare(x.getSalary(), y.getSalary()));
         * System.out.println(op.get().getSalary());
         */
        Optional<Double> op = emps.stream().map(Employee::getSalary).min(Double::compare);
        System.out.println(op.get());
    }
    //max
    @Test
    public void test7() {
        Optional<Employee> op = emps.stream().max((x,y)->Double.compare(x.getSalary(), y.getSalary()));
        System.out.println(op.get());
    }
    
    //count
    @Test
    public void test6() {
        long count = emps.stream().count();
        System.out.println(count);
    }
    
    
    //findAny
    @Test
    public void test5() {
         Optional<Employee> op = emps.stream().filter((e)->e.getStatus().equals(Status.FREE)).findAny();
         System.out.println(op.get());
    }
    
    //findFirst
    @Test
    public void test4() {
        Optional<Employee> op = emps.stream().sorted((x,y)->Double.compare(x.getSalary(), y.getSalary())).findFirst();
        //op.orElse(null)
        System.out.println(op.get());
    }
    
    //noneMatch
    @Test
    public void test3() {
        boolean b1 = emps.stream().noneMatch((e)->e.getStatus().equals(Status.BUSY));
        System.out.println(b1);
    }
    
    //anyMatch
    @Test
    public void test2() {
        boolean b1 = emps.stream().anyMatch((e)->e.getStatus().equals(Status.BUSY));
        System.out.println(b1);
    }
    //allMatch
    @Test
    public void test1() {
        boolean b1 = emps.stream().allMatch((e)->e.getStatus().equals(Status.BUSY));
        System.out.println(b1);
    }
}
2.規約與收集

!image

? 歸約:reduce(T identity, BinaryOperator) / reduce(BinaryOperator) 可以將流中的資料反復結合起來,得到一個值,通常和map合用,map-reduce模式
? 收集:collect 將流轉換成其他形式;接收一個 Collector 介面的實作,用于給流中元素做匯總的方法
public class TestStreamAPI6 {
    List<Employee> emps = Arrays.asList(new Employee(1, "張三", 14, 5444.42, Status.FREE),
            new Employee(2, "李四", 39, 3434.15, Status.BUSY), new Employee(3, "李四", 39, 3434.15, Status.VOCATION),
            new Employee(4, "王五", 31, 5425.55, Status.FREE), new Employee(5, "趙六", 31, 2544.42, Status.BUSY),
            new Employee(6, "陳七", 98, 944.42, Status.BUSY));
    // 終止操作
    // 收集:collect 將流轉換成其他形式;接收一個 Collector 介面的實作,用于給流中元素做匯總的方法
    //連接
    @Test
    public void test9() {
        String string = emps.stream().map(Employee::getName).collect(Collectors.joining(","));
        System.out.println(string);
    }
    @Test
    public void test8() {
        DoubleSummaryStatistics collect = emps.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(collect);
    }
    // 磁區/分片
    @Test
    public void test7() {
        Map<Boolean, List<Employee>> map = emps.stream().collect(Collectors.partitioningBy((e) -> e.getAge() > 30));
        System.out.println(map);
    }
    // 多級分組
    @Test
    public void test6() {
        // 按狀態分組
        Map<Status, Map<Object, List<Employee>>> map = emps.stream()
                .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
                    if (e.getAge() > 30) {
                        return "青年";
                    } else {
                        return "老家伙";
                    }
                })));
        System.out.println(map);
    }
    // 分組
    @Test
    public void test5() {
        // 按狀態分組
        Map<Status, List<Employee>> map = emps.stream().collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println(map);
    }
    @Test
    public void test4() {
        // 總數
        Long collect = emps.stream().collect(Collectors.counting());
        System.out.println("總數:" + collect);
        // 工資平均值
        Double averag = emps.stream().collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println("工資平均值:" + averag);
        // 工資總和
        Double sumSalary = emps.stream().collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println("工資總和:" + sumSalary);
        // 工資最大值
        Optional<Employee> op = emps.stream()
                .collect(Collectors.maxBy((x, y) -> Double.compare(x.getSalary(), y.getSalary())));
        System.out.println("最大工資:" + op.get());
        // 工資最小值
        Optional<Double> op2 = emps.stream().map(Employee::getSalary).collect(Collectors.minBy(Double::compare));
        System.out.println("最小工資:" + op2.get());
    }
    @Test
    public void test3() {
        // 收集所有的員工姓名
        // list中
        List<String> list = emps.stream().map(Employee::getName).collect(Collectors.toList());
        System.out.println(list);
        System.out.println("--------");
        // set中
        Set<String> set = emps.stream().map(Employee::getName).collect(Collectors.toSet());
        System.out.println(set);
        System.out.println("--------");
        // 其它集合中
        HashSet<String> hashSet = emps.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
        System.out.println(hashSet);
    }
    // 歸約:reduce(T identity, BinaryOperator) / reduce(BinaryOperator)
    // 可以將流中的資料反復結合起來,得到一個值
    @Test
    public void test2() {
        // 計算工資總和
        Optional<Double> op = emps.stream().map((e) -> e.getSalary()).reduce(Double::sum);
        System.out.println(op.get());
    }
    @Test
    public void test1() {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer sum = list.stream().reduce(0, (x, y) -> x + y);
        System.out.println(sum);
    }
}

5.并行流與串行流

!image.png

? 并行流:就是把一個內容分成幾個資料塊,并用不同的執行緒分別處理每個資料塊的流
? Java 8 中將并行進行了優化,我們可以很容易的對資料進行操作;Stream API 可以宣告性地通過 parallel() 與 sequential() 在并行流與串行流之間切換

fork/join

public class ForkJoinCalculate extends RecursiveTask<Long>{
    private static final long serialVersionUID = 1L;
    private long start;
    private long end;
    private static final long THRESHPLD =1000;
    /**
     * @param start
     * @param end
     */
    public ForkJoinCalculate(long start, long end) {
        super();
        this.start = start;
        this.end = end;
    }
    @Override
    protected Long compute() {
        long length=end-start;
        if(length<=THRESHPLD) {
            long sum=0;
            for(long i=start;i<=end;i++) {
                sum+=i;
            }
            return sum;
        }else {
            long middle = (start + end) / 2;
            ForkJoinCalculate left=new ForkJoinCalculate(start, middle);
            left.fork();//拆分成子任務,同時加入執行緒佇列
            
            ForkJoinCalculate right=new ForkJoinCalculate(middle+1, end);
            right.fork();
            
            return left.join()+right.join();
            
        }
        
    }
    
}
//fork/join  數值越大,越能體現性能
    @Test
    public void test1() {
        Instant start = Instant.now();
        ForkJoinPool pool = new ForkJoinPool();
        ForkJoinTask<Long> task=new ForkJoinCalculate(0, 100000000);
        Long sum = pool.invoke(task);
        System.out.println(sum);
        Instant end = Instant.now();
        System.out.println("耗費時間:"+Duration.between(start, end).toMillis()+"毫秒");//70
    }
    
    //普通for回圈
    @Test
    public void test2() {
        Instant start = Instant.now();
        long sum=0;
        for(int i=0;i<=100000000;i++) {
            sum+=i;
        }
        System.out.println(sum);
        Instant end = Instant.now();
        System.out.println("耗費時間:"+Duration.between(start, end).toMillis()+"毫秒");//30
    }

java8并行流 parallel 底層 fork/join

//java8并行流 parallel()
@Test
public void test3(){
    Instant start = Instant.now();
    OptionalLong op = LongStream.rangeClosed(0, 1000000000L)
            .parallel()
            .reduce(Long::sum);
    System.out.println(op.getAsLong());
    Instant end = Instant.now();
    System.out.println("耗費時間:"+Duration.between(start, end).toMillis()+"毫秒");//49->257毫秒
}

6.Optional

定義:Optional 類 (java.util.Optional) 是一個容器類,代表一個值存在或不存在,原來用 null
表示一個值不存在,現在用 Optional 可以更好的表達這個概念;并且可以避免空指標例外

常用方法:

	? Optional.of(T t):創建一個 Optional 實體
	? Optional.empty(T t):創建一個空的 Optional 實體
	? Optional.ofNullable(T t):若 t 不為 null,創建 Optional 實體,否則空實體
	? isPresent():判斷是否包含某值
	? orElse(T t):如果呼叫物件包含值,回傳該值,否則回傳 t
	? orElseGet(Supplier s):如果呼叫物件包含值,回傳該值,否則回傳 s 獲取的值
	? map(Function f):如果有值對其處理,并回傳處理后的 Optional,否則回傳 Optional.empty()
	? flatmap(Function mapper):與 map 相似,要求回傳值必須是 Optional
public class TestOptiona {
    /*
     * Optional.of(T t):創建一個 Optional 實體 
     * Optional.empty(T t):創建一個空的 Optional 實體
     * Optional.ofNullable(T t):若 t 不為 null,創建 Optional 實體,否則空實體
     * isPresent():判斷是否包含某值 
     * orElse(T t):如果呼叫物件包含值,回傳該值,否則回傳 t 
     * orElseGet(Supplier s):如果呼叫物件包含值,回傳該值,否則回傳 s 獲取的值 
     * map(Function f):如果有值對其處理,并回傳處理后的 Optional,否則回傳Optional.empty() 
     * flatmap(Function mapper):與 map 相似,要求回傳值必須是 Optional
     * 
     */
    @Test
    public void test8() {
        Optional<Employee> op = Optional.ofNullable(new Employee(1, "張三", 110, 55440.14, Status.BUSY));
        Optional<String> flatMap = op.flatMap((e)->Optional.of(e.getName()));
        System.out.println(flatMap.get());
    }
    
    @Test
    public void test7() {
        Optional<Employee> op = Optional.ofNullable(new Employee(1, "張三", 110, 55440.14, Status.BUSY));
        Optional<String> map = op.map((e)->e.getName());
        System.out.println(map.get());
    }
    
    @Test
    public void test6() {
        Optional<Employee> op = Optional.ofNullable(new Employee());
        Employee emp=op.orElseGet(()-> new Employee(1, "張三", 110, 55440.14, Status.BUSY));
        System.out.println(emp);
    }
    @Test
    public void test5() {
    
        Optional<Employee> op = Optional.ofNullable(new Employee());
        Employee emp=op.orElse(new Employee(1, "張三", 110, 55440.14, Status.BUSY));//避免空指標例外
        System.out.println(emp);
    }
    
    
    @Test
    public void test4() {
        //ofNullable是empty和of的綜合
        Optional<Employee> op = Optional.ofNullable(new Employee());
        if(op.isPresent()) {
            Employee emp = op.get();//空指標報錯位置
            System.out.println(emp);
        }
        
    }
    
    @Test
    public void test3() {
        //ofNullable是empty和of的綜合
        Optional<Employee> op = Optional.ofNullable(new Employee());
    
        Employee emp = op.get();//空指標報錯位置
        System.out.println(emp);
    }
    
    @Test
    public void test2() {
        Optional<Employee> op = Optional.empty();
        Employee emp = op.get();//空指標報錯位置
        System.out.println(emp);
    }
    @Test
    public void test1() {
        Optional<Employee> op = Optional.of(new Employee());//傳入null空指標報錯位置
        Employee emp = op.get();
        System.out.println(emp);
    }
}

7.介面中的默認方法與靜態方法

1.默認方法

public interface MyFun {
    default String getName() {
        return "libo";
    }
    default Integer getAge() {
        return 22;
    }
}
public class MyClass {
    public String getName() {
        return "MyClass類";
    }
}
public class SubClass extends MyClass implements MyFun{
}
public static void main(String[] args) {
        SubClass sc=new SubClass();
        String name = sc.getName();//類優先原則
        System.out.println(name);
    }
public interface MyInterfaces {
    default String getName() {
        return "MyInterfaces介面";
    }
}
public class SubClass2 implements MyFun,MyInterfaces{
    //實作多介面,并有同方法,必須實作該方法
    @Override
    public String getName() {
        return MyFun.super.getName();
    }
}

2.靜態方法

public interface MyInterfaces {
    default String getName() {
        return "MyInterfaces介面";
    }
    
    public static void show() {
        System.out.println("介面中的靜態方法");
    }
}
MyInterfaces.show();

8.新時間API

1.傳統時間存在安全問題

    public static void main(String[] args) throws Exception {
        //存在執行緒安全問題
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        Callable<Date> task = () -> sdf.parse("20210111");
        ExecutorService pool = Executors.newFixedThreadPool(10);
        ArrayList<Future<Date>> result = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            result.add(pool.submit(task));
        }
        for (Future<Date> future : result) {
            System.out.println(future.get());
        }
        pool.shutdown();
    }
//執行緒安全
public class DateFormatThreadLocal {
    private static final ThreadLocal<DateFormat> df = ThreadLocal
            .withInitial(() -> new SimpleDateFormat("yyyyMMdd"));
    public static Date convert(String source) throws ParseException {
        return df.get().parse(source);
    }
}
public static void main(String[] args) throws Exception {
        //存在執行緒安全問題
        //SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        //Callable<Date> task = () -> sdf.parse("20210111");
        
        Callable<Date> task =() ->DateFormatThreadLocal.convert("20181212");
        ExecutorService pool = Executors.newFixedThreadPool(10);
        ArrayList<Future<Date>> result = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            result.add(pool.submit(task));
        }
        for (Future<Date> future : result) {
            System.out.println(future.get());
        }
        pool.shutdown();
    }
    public static void main(String[] args) throws Exception {
        //java8新時間
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
        Callable<LocalDate> task =() ->LocalDate.parse("20181212",dtf);
        ExecutorService pool = Executors.newFixedThreadPool(10);
        ArrayList<Future<LocalDate>> result = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            result.add(pool.submit(task));
        }
        for (Future<LocalDate> future : result) {
            System.out.println(future.get());
        }
        pool.shutdown();
    }

2.本地時間

image.png
常用方法:

方法名回傳值型別解釋
now( )static LocalDateTime從默認時區的系統時鐘獲取當前日期
of(int year, int month, int dayOfMonth, int hour, int minute, int second)static LocalDateTime從年,月,日,小時,分鐘和秒獲得 LocalDateTime的實體,將納秒設定為零
plus(long amountToAdd, TemporalUnit unit)LocalDateTime回傳此日期時間的副本,并添加指定的數量
get(TemporalField field)int從此日期時間獲取指定欄位的值為 int
public class TestLocalDateTime {
    //1.LocalDate  LocalTime  LocalDateTime 
    
    @Test
    public void  test1() {
        //獲取當前時間日期 now
        LocalDateTime ldt=LocalDateTime.now();
        System.out.println(ldt);
        
        //指定時間日期 of
        LocalDateTime ldt2 = LocalDateTime.of(2021, 8, 14, 16, 24, 33);
        System.out.println(ldt2);
        
      //加 plus
        LocalDateTime ldt3 = ldt2.plusYears(2);
        System.out.println("加兩年:"+ldt3);
        //減 minus
        LocalDateTime ldt4 = ldt2.minusMonths(3);
        System.out.println("減三個月:"+ldt4);
        //獲取指定的你年月日時分秒... get
        System.out.println("年"+ldt2.getDayOfYear());
        System.out.println("時"+ldt2.getHour());
        System.out.println("秒"+ldt2.getSecond());
    }
}

3.時間戳

Instant:以 Unix 元年 1970-01-01 00:00:00 到某個時間之間的毫秒值

// 時間戳
    // Instant:以 Unix 元年 1970-01-01 00:00:00 到某個時間之間的毫秒值
    @Test
    public void test2() {
        // 默認獲取 UTC 時區 (UTC:世界協調時間)0時區時間
        Instant ins1 = Instant.now();
        System.out.println(ins1);
        // 帶偏移量的時間日期 (如:UTC + 8)
        OffsetDateTime odt = ins1.atOffset(ZoneOffset.ofHours(8));
        System.out.println(odt);
        
         //轉換成對應的毫秒值
        long milli = ins1.toEpochMilli();
        System.out.println(milli);
         //構建時間戳
        Instant ins2 = Instant.ofEpochSecond(6000);
        System.out.println(ins2);//1970-01-01T01:40:00Z
        
    }

4.時間/日期之間的間隔

? Duration:計算兩個時間之間的間隔
? Period:計算兩個日期之間的間隔
 //Duration:計算兩個時間之間的間隔
   // Period:計算兩個日期之間的間隔
    
     //Duration:計算兩個時間之間的間隔
    @Test
    public void test3() {
        
        Instant ins1 = Instant.now();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Instant ins2 = Instant.now();
        Duration duration = Duration.between(ins1, ins2);
        System.out.println(duration.toMillis());
        
    }
    
    // Period:計算兩個日期之間的間隔
    @Test
    public void test4() {
        
        LocalDate ld1 = LocalDate.of(2019, 11, 11);
        LocalDate ld2 = LocalDate.now();
        Period period = Period.between(ld1, ld2);
        System.out.println(period.getDays());
        
        
    }

5.時間校正器

image.png

// TemporalAdjusters 時間校正器
    @Test
    public void test1() {
        
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);
        
         //指定日期時間中的 年 月 日 ...
        LocalDateTime ldt2 = ldt.withDayOfMonth(10);//將月中的時間制定成10
        System.out.println(ldt2);
        
         //指定時間校正器
        LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
        System.out.println(ldt3);
        
        //自定義時間校正器:下一個作業日是什么時候
        
        LocalDateTime ldt4=ldt.with((l)->{
            LocalDateTime ldt0 =(LocalDateTime) l; 
            DayOfWeek dow = ldt0.getDayOfWeek();
             if (dow.equals(DayOfWeek.FRIDAY)) {
                    return ldt0.plusDays(3);
                } else if (dow.equals(DayOfWeek.SATURDAY)) {
                    return ldt0.plusDays(2);
                } else {
                    return ldt0.plusDays(1);
                }
    
        });
        System.out.println(ldt4);
    }

6.時間格式化

 DateTimeFormatter:格式化時間 / 日期
//DateTimeFormatter:格式化時間 / 日期
    @Test
    public void test1() {
        DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(dtf.format(ldt));
        
         //自定義格式化 ofPattern
        
        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String d2 = dtf2.format(ldt);
        System.out.println(d2);
        
        //決議
        LocalDateTime ldt2 = ldt.parse(d2,dtf2);
        System.out.println(ldt2);
    }

image.png
7.時區的處理

? ZonedDate
? ZonedTime
? ZonedDateTime
// 時區的處理
    // ZonedDate
    // ZonedTime
    // ZonedDateTime
    
    @Test
    public void test1() {
         //查看支持的時區
        Set<String> set = ZoneId.getAvailableZoneIds();
        set.forEach(System.out::println);
        
        //指定時區
        LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of("Chile/Continental"));
        System.out.println(ldt1);
        
        //帶時區
        ZonedDateTime zdt1  = ldt1.atZone(ZoneId.of("Chile/Continental"));
        System.out.println(zdt1);
    }

9.重復注解與注解型別

//容器類
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)//宣告周期
public @interface MyAnnotations {
    MyAnnotation[] value();
}
//自定義注解類
@Repeatable(MyAnnotations.class)//制定容器
@Target({ TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE })
@Retention(RetentionPolicy.RUNTIME) // 宣告周期
public @interface MyAnnotation {
    String value() default "Java 8";
}
     //重復注解
    @Test
    @MyAnnotation("Hello")
    @MyAnnotation("World")
    public void test01() throws NoSuchMethodException {
        Class<TestAnnotation> clazz = TestAnnotation.class;
        Method test01 = clazz.getMethod("test01");
        MyAnnotation[] mas = test01.getAnnotationsByType(MyAnnotation.class);
        for (MyAnnotation ma : mas) {
            System.out.println(ma.value());
        }
    }

Java 8 新增注解:新增ElementType.TYPE_USE
和ElementType.TYPE_PARAMETER(在Target上)

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/282913.html

標籤:java

上一篇:專案中用了spring這些牛逼的開發技巧,經理請我吃飯了

下一篇:SpringMVC框架如何與Junit整合,看這個就夠了

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more