Java8新機能の研究ノート
1つのメインコンテンツ
- ラムダ式
- 機能インタフェース
- そして、参照は、コンストラクタメソッドを引用しました
- ストリームAPI
- デフォルトのインターフェイスメソッド、および静的メソッド
- 新しい日付と時刻のAPI
- その他の新機能
2シンプル
- 添加速度に加えて、 - (> +一覧アレイ/赤黒木以前アレイに加えリストから)、ConcurrentHashMapの(CASアルゴリズム)より速く、HashMapの、HashSetの基礎となるリストのハッシュアルゴリズムを変更します
- コードより簡潔な(ラムダ式)
- パワフルStreamAPI(オペレーショナルデータ収集が非常に便利です)
- 容易に平行
- オプションのヌルポインタ最大化還元容器クラス
3つのラムダ式
ラムダ匿名関数でコードの一部を送信することができるように、ラムダ式は、(画像データを送信するためのコードと同じ)を理解することができます。あなたは、よりシンプルで柔軟なコードを書くことができます。よりコンパクトなコードスタイルとしては、Java言語のスキルが向上しています。
ケース:
//原来的匿名内部类
public void test1(){
//比较器
Comparator<Integer> com=new Comparator<Integer>(){
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
}
//使用 Lambda表达式
public void test2(){
//x,y为传入的参数 形参,Integer.compare(x,y) 为方法内内容
Comparator<Integer> com=(x,y)->Integer.compare(x,y);
}
示されるように、新しい構文、よりコンパクトなコードは、->
ラムダの左および右の部分に、ラムダ演算子をいいます。
左:ラムダ式のために必要なすべてのパラメータを指定します
右:実行される身体指定ラムダ、ラムダ式機能
構文は、3つのケースに分けています
構文:引数なし戻り値なしに、ラムダ本体だけで声明
Runable run = ()->System.out.println("执行的语句")
(タスクスレッドを作成します)二つの構文は:ラムダには引数が必要です
Comsumer com = (args)->System.out.println(args)
もし一つだけのパラメータできないブラケット
args->System.out.println(args)
(Comsumerパラメータを受信プログラミング・インターフェース、消費パターンの関数として、ノーリターン値)三つの構文は:ラムダは、2つのパラメータを取り、値を返します。
三つの構文:ラムダは、3つのパラメータを必要とし、
BinaryOperato bin =(x,y)->{ return x+y ;};
(バイナリインタフェース機能は、2つの数値を受け取り、同じタイプの数を返します)一つだけ実行文の場合は、リターンと中括弧を省略することができます
BinaryOperato bin =(x,y)-> x+y
上記のパラメータブラケット、書込みパラメータのないタイプは、この理由は、コンパイラができ呼ばれる一般的な文脈、方法、推論されたタイプ、「型推論。」
4機能インタフェース
関数インタフェースと呼ばれるだけ抽象インタフェースメソッドは、含まれています。
文法は上記のラムダルールでは、右側の式は、操作の実際の内容は、インタフェースを達成することであるが、インターフェースは、それゆえ、ラムダ式に属している必要がありますどのような2つの抽象クラス、この操作の内容を、持っている場合、サポート機能のインタフェースがなければなりません。
あなたは、ラムダ式を経由してインタフェースのオブジェクトを作成することができます。(ラムダ式が対象例外場合スローされ、例外はターゲット・インタフェースの抽象メソッドで宣言する必要があります)。
javadocはまた、このインターフェースが機能インタフェースであるという記述が含まれている間私たちは、それが機能的インタフェースであるかどうかを確認することができそう、ノート@FunctionalInterface任意の関数インタフェース上で使用することができます。
パラメータとして渡されるラムダ式:パラメータとして渡されるラムダ式に、ラムダ式を受信したパラメータのタイプは、機能インタフェースのラムダ式のタイプと互換性がなければなりません。
ケース:その関数インタフェースの定義
@FunctionalInterface
public interface MyFun {
public Integer getValue(Integer num);
}
ケース:機能インタフェースの定義、およびパラメータ転送の方法として
//需求:对一个数进行运算
@Test
public void test6(){
//只一个函数式接口,就可以进行多种运算
Integer num=operation(100, (x)->x*x);
System.out.println(num);
System.out.println(operation(200, (y)->y+200));
}
public Integer operation(Integer num,MyFun mf){
return mf.getValue(num);
}
ケース:パラメータとして渡されたラムダを使用して、(名前と同じ年齢のプレスよりも古い、)カスタムオーダーを介して2人の従業員を比較するために、Collections.sort()メソッドを呼び出します。
List<Employee> employees=Arrays.asList(
new Employee("张三",18,9496.2),
new Employee("李四",52,2396.2),
new Employee("王五",56,996.2),
new Employee("赵六",8,94.2)
);
@Test
public void test1(){
//使用Lambda 可以轻松的定义比较规则,
Collections.sort(employees, (e1,e2)->{
if(e1.getAge()==e2.getAge()){
return e1.getName().compareTo(e2.getName());
}else{
return Integer.compare(e1.getAge(), e2.getAge());
}
});
}
私たちは、ラムダ式を使用する便宜上、Javaは私たちに組み込み関数インタフェースを提供します、
内蔵4つのインターフェース機能のJava
消費者
:消費者インタフェース 空隙は、(T tを)受け入れます。
サプライヤー
:供給インタフェース Tは、get()は、
機能<T、R>:関数インタフェース
Rは、(T tを)適用します。
Preicate
:アサーションインタフェース ブーリアンテスト(T tの);
その他のインタフェース:
5及び参考引用したコンストラクタメソッド
3つの主な方法は、構文を引用があります。
:: Objectインスタンスメソッド名
::クラスの静的メソッド名
::クラスインスタンスメソッド名
注意:
1、身体ラムダパラメータリストとメソッドの戻り値の型、戻り値の型と一致抽象関数とメソッドとのインタフェース関数のリストを呼び出します!
図2に示すように、最初のパラメータは、メソッドのパラメータリストラムダ発信者の一例であり、2番目のパラメータはメソッドのパラメータの例であれば、
(X、Y) - > x.equals(y)は、文字列を書くことができる::クラス名を等しく::方法を用いることができます
public class TestMethodRef {
//对象::实例方法名
@Test
public void test1(){
PrintStream ps1=System.out; //打印流对象
Consumer<String> con=(x)->ps1.println(x);
//可以写成下面的样子
PrintStream ps=System.out;
Consumer<String> con1=ps::println;//相当于上面,引用了ps对象的println()方法
Consumer<String> con2=System.out::println;
}
@Test
public void test2(){
final Employee emp=new Employee(); //匿名内部类中引用外部的对象,该对象必须为final
Supplier<String> sup=()->emp.getName();//代替匿名内部类 (jdk1.8后 引用的对象就算没有显式 的加final ,也可以正常使用了,但这个只是语法糖,其底层还是会自动加上final,如果后面对其改变,会 报错)
Supplier<Integer> sup2=emp::getAge; // 引用emp对象的方法,实现抽象方法,进行对外供给
Integer num=sup2.get();
}
//类::静态方法名
@Test
public void test3(){
Comparator<Integer> com=(x,y)->Integer.compare(x,y);
Comparator<Integer> com1=Integer::compare;//引用静态方法
}
//类::实例方法名
@Test
public void test4(){
BiPredicate<String,String> bp=(x,y)->x.equals(y);
BiPredicate<String, String> bp2=String::equals; //第一个参数是调用者,第二个参数是实参
}
コンストラクタ参照:
フォーマット:クラス名::新しいです
インターフェース機能と組み合わせて、機能インタフェースは、自動的な方法と互換性があります。コンストラクタメソッドは、一貫性の抽象メソッドのインタフェースパラメータリストの割り当て、構成、およびパラメータリストを参照することによって定義することができます
//构造器引用
@Test
public void test5(){
Supplier<Employee> sup=()->new Employee();
//构造器引用方式
Supplier<Employee> sup2=Employee::new;//使用无参构造器
Employee emp=sup2.get(); //引用Employee构造器进行供给
//带参的构造器
Function<Integer,Employee> fun2=(x)->new Employee(x);
BiFunction<String,Integer,Employee> bf=Employee::new;//也这么写,抽象方法中的参数类型会自动 匹配相对应的构造器
}
配列参照:
方法の配列を作成するための参考資料
//数组引用
@Test
public void test6(){
Function<Integer,String[]> fun=(x)->new String[x];
String[] strs=fun.apply(10);
System.out.println(strs.length);
Function<Integer,String[]> fun2=String[]::new;
String[] str2=fun2.apply(20);
System.out.println(str2.length);
}
}
6ストリームアピ
Java8で最も重要な変更点のうちの2つを持っています。
最初は、ラムダ式です。
もう一つは、ストリームAPIである(java.util.stream。*)。
ストリーム処理は、あなたはそれが一連の操作は非常に複雑な検索、フィルタリングおよびマッピングデータや他の操作を行うことができますようにしたいように指定することができ、キー抽象Java8コレクションです。SQLデータベースクエリの実行を使用するのと同様のデータ収集を、操作するためのストリームAPIを使用してください。ストリームAPIは、並行して操作を実行するために使用することができます。
- ストリームは、記憶素子を所有していません。
- ストリームは、ソースオブジェクトを変更しません。代わりに、彼らは新しいストリームを保持した結果を返します。
- ストリーム遅延動作が行われます。これは、彼らが唯一の(優れた性能)の実施結果まで待機する必要があることを意味します
ストリーム3ステップの操作
- ストリームが作成
ストリームを得る:(コレクション、アレイなど)のデータソースを - 中間作動
鎖中間操作、データソースのデータ処理 - 操作(操作端末)終了
終了操作、中間操作鎖を実行し、結果を生み出します
ストリームを作成します。
ストリーム()またはparallelStream()を経由してコレクション内のメソッドのセットを提供します
ストリーム<E>ストリームを()デフォルト : 配列戻り
デフォルトストリーム<E> parallelStreamを() :パラレルストリームを返します()ツールの静的メソッド・ストリーム・アレイを通る流れの配列を取得し
静的<T>ストリーム<T>ストリーム(T []配列)タイプのストリームの任意のタイプの受信の配列を返します
基本的なタイプに対応する配列を扱うことができるオーバーロード:
パブリック静的IntStreamストリーム(INT []配列)
パブリック静的LongStreamストリーム(長い[]配列)
パブリック静的DoubleStreamストリーム(ダブル[]配列)Streamクラスの静的メソッドで作成されたストリームの値を表示することにより、)(の。これは、任意の数のパラメータを受け取ることができます。
<T>ストリーム<T>(T ...の値)の公開静的:直接型のストリームの型の値を作成し、任意の数の受信
無制限のストリームを作成します。
あなたは、静的メソッドStream.iterate()とStream.generate()を使用し、無限のストリームを作成することができます。
迭代
パブリック静的<T>ストリーム<T>の反復(最終T種子、最終UnaryOperator <T> f)の
生成
のpublic static <T>ストリーム<T>を生成(サプライヤー<T> S)
こちらの場合は、次のとおりです。
//创建Stream
@Test
public void test1(){
//1.可以通过Collection 系列集合提供的stream()或parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream1 = 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.创建无限流
//迭代
Stream<Integer> stream4=Stream.iterate(0, (x) -> x+2);
stream4.limit(10).forEach(System.out::println);
//生成
Stream.generate(() -> Math.random())
.limit(5)
.forEach(System.out::println);
}
中級操作
そうでなければ操作は、任意の処理を実行しないように、中間の操作複数のパイプライン動作は、終了トリガしない限り、パイプラインを形成するように接合されてもよいです!使い捨ての処理動作が終了すると、「遅延評価。」
- 濾過およびスライス
//中间操作
List<Employee> employees=Arrays.asList(
new Employee("张三",18,9999.99),
new Employee("李四",58,5555.55),
new Employee("王五",26,3333.33),
new Employee("赵六",36,6666.66),
new Employee("田七",12,8888.88),
new Employee("田七",12,8888.88)
);
//Steam对象执行中间操作时,会返回Steam对象,实现链式调用
//内部迭代:迭代操作由 Stream API 完成
@Test
public void test1(){
//中间操作:不会执行任何操作(没有终止操作)
//过滤操作,过滤规则为传入的断言函数式接口来定义(本案例为年龄超过35岁的)
Stream<Employee> stream=employees.stream()
.filter((e) -> e.getAge()>35 );
//终止操作:一次性执行全部内容,即 惰性求值(执行这一句代码时,上面的中间操作才会执行)
stream.forEach(System.out::println);
}
//外部迭代
@Test
public void test2(){
Iterator<Employee> it=employees.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
@Test
//limit中间操作 在找到指定的条数数后,会自动切断流的迭代
public void test3(){//发现“短路”只输出了两次,说明只要找到 2 个 符合条件的就不再继续迭代
employees.stream()
.filter((e)->{
System.out.println("短路!");
return e.getSalary()>5000;
})
.limit(2)
.forEach(System.out::println);
}
@Test
public void test4(){
employees.stream()
.filter((e)->e.getSalary()>5000)
.skip(2)//跳过前两个
.distinct()//去重,注意:需要Employee重写hashCode 和 equals 方法
.forEach(System.out::println);
}
- マッピング
@Test
public void test5(){
List<String> list=Arrays.asList("aaa","bbb","ccc","ddd");
//将作用于其中每一个元素
list.stream()
.map((str)->str.toUpperCase())
.forEach(System.out::println);
employees.stream()
.map(Employee::getName)
.forEach(System.out::println);
//将其中的每个元素都映射成一个流(该案例为把每个字符串变成字符集合的流)
Stream<Stream<Character>> stream=list.stream()
.map(TestStreamAPI2::filterChatacter);
//遍历主流 ,取出其中每个流,再遍历每个流,得到每个字符
stream.forEach((sm)->{
sm.forEach(System.out::println);
});
System.out.println("------------------------");
//将其中每个元素变成一个流后,并合并这些流,变成一个流,所有的元素在一起
Stream<Character> sm=list.stream()
.flatMap(TestStreamAPI2::filterChatacter);
sm.forEach(System.out::println);
}
public static Stream<Character> filterChatacter(String str){
List<Character> list=new ArrayList<>();
for (Character ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}
@Test
public void test6(){
//map和flatMap的关系 类似于 add(Object)和addAll(Collection coll)
List<String> list=Arrays.asList("aaa","bbb","ccc","ddd");
List list2=new ArrayList<>();
list2.add(11);
list2.add(22);
list2.addAll(list);
}
- シーケンス
Javaの`` `
@Test
ます。public void TEST7(){
//デフォルトの天然注文
一覧
list.stream()
(.sorted)
.forEach(System.outに::のprintln)。
System.out.println("------------------------");
//按照自定义的排序规则
employees.stream()
.sorted((e1,e2)->{
if(e1.getAge().equals(e2.getAge())){
return e1.getName().compareTo(e2.getName());
}else{
return e1.getAge().compareTo(e2.getAge());
}
}).forEach(System.out::println);
}
```
操作の終了
ターミナルは、パイプラインの流れからの結果を生成します。その結果、いないストリームは、例えば、任意の値を指定できます:リスト、整数、あるいは無効
- マッチを探します
List<Employee> employees=Arrays.asList(
new Employee("张三",18,9999.99,Status.FREE),
new Employee("李四",58,5555.55,Status.BUSY),
new Employee("王五",26,3333.33,Status.VOCATION),
new Employee("赵六",36,6666.66,Status.FREE),
new Employee("田七",12,8888.88,Status.BUSY)
);
/*
* 查找与匹配
*
*/
@Test
public void test1(){
boolean b1=employees.stream()//allMatch-检查是否匹配所有元素(状态都为BUSY的)
.allMatch((e)->e.getStatus().equals(Status.BUSY));
System.out.println(b1);//false
boolean b2=employees.stream()//anyMatch-检查是否至少匹配一个元素(至少有一个是BUSY的)
.anyMatch((e)->e.getStatus().equals(Status.BUSY));
System.out.println(b2);//true
boolean b3=employees.stream()//noneMatch-检查是否没有匹配所有元素(一个都不是)
.noneMatch((e)->e.getStatus().equals(Status.BUSY));
System.out.println(b3);//false
//findFirst-返回第一个元素//Optional是Java8中避免空指针异常的容器类
Optional<Employee> op=employees.stream()
.sorted((e1,e2)->Double.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
System.out.println(op.get());//Employee [name=王五, age=26, salary=3333.33, Status=VOCATION]
Optional<Employee> op2=employees.parallelStream()//findAny-返回当前流中的任意元素
.filter((e)->e.getStatus().equals(Status.FREE))
.findAny();
System.out.println(op2.get());//Employee [name=赵六, age=36, salary=6666.66, Status=FREE]
Long count=employees.stream()//count-返回流中元素的总个数
.count();
System.out.println(count);//5
Optional<Employee> op3=employees.stream()//max-返回流中最大值(比较规则可以定义,倒过来放)
.max((e1,e2)->Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(op3.get());//Employee [name=张三, age=18, salary=9999.99, Status=FREE]
Optional<Double> op4=employees.stream()//min-返回流中最小值
.map(Employee::getSalary)
.min(Double::compare);
System.out.println(op4.get());//3333.33
}
- 規程
可
/*
* 归约(可以和map相结合使用)
* reduce(T identity,BinaryOperator b) / reduce(BinaryOperator b)-可以将流中元素反复结合起来,得到一个值。
*/
@Test
public void test3(){
List<Integer> list=Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum=list.stream()//reduce(T identity,BinaryOperator b)
.reduce(0, (x,y)->x+y);//0为起始值
System.out.println(sum);
System.out.println("--------------------------");
Optional<Double> op=employees.stream()//reduce(BinaryOperator b)//没有起始值,map返回可能为空,所以返回Optional类型
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(op.get());
}
集まります
コレクターは、インターフェイスメソッドは、対流が(そのようなリスト、セット、地図を集めるなど)の収集を行う方法を決定し実施しています。しかし、コレクターのユーティリティクラスを使用すると、簡単に共通コレクタインスタンス、次の表の特定の方法および例を作成することができ、多くの静的メソッドを提供します。
/*
* 收集
* collect-将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。
*/
@Test
public void test4(){
List<String> list=employees.stream()
.map(Employee::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("----------------------------");
Set<String> set=employees.stream()
.map(Employee::getName)
.collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("----------------------------");
HashSet<String> hs=employees.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(HashSet::new));
hs.forEach(System.out::println);
System.out.println("----------------------------");
//总和
Long count=employees.stream()
.collect(Collectors.counting());
System.out.println(count);
//平均值
Double avg=employees.stream()
.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(avg);
//总和
Double sum=employees.stream()
.collect(Collectors.summingDouble(Employee::getSalary));
System.out.println(sum);
//最大值
Optional<Employee> max=employees.stream()
.collect(Collectors.maxBy((e1,e2)->Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(max.get());
//最小值
Optional<Double> min=employees.stream()
.map(Employee::getSalary)
.collect(Collectors.minBy(Double::compare));
System.out.println(min.get());
System.out.println("----------------------------");
//分组
Map<Status,List<Employee>> map=employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(map);//{FREE=[Employee [name=张三, age=18, salary=9999.99, Status=FREE], Employee [name=赵六, age=36, salary=6666.66, Status=FREE]], VOCATION=[Employee [name=王五, age=26, salary=3333.33, Status=VOCATION]], BUSY=[Employee [name=李四, age=58, salary=5555.55, Status=BUSY], Employee [name=田七, age=12, salary=8888.88, Status=BUSY]]}
//多级分组
Map<Status,Map<String,List<Employee>>> map2=employees.stream()
.collect( Collectors.groupingBy( Employee::getStatus,Collectors.groupingBy((e)->{
if(e.getAge()<=35){
return "青年";
}else if(e.getAge()<=50){
return "中年";
}else{
return "老年";
}
}) ) );
System.out.println(map2);//{FREE={青年=[Employee [name=张三, age=18, salary=9999.99, Status=FREE]], 中年=[Employee [name=赵六, age=36, salary=6666.66, Status=FREE]]}, VOCATION={青年=[Employee [name=王五, age=26, salary=3333.33, Status=VOCATION]]}, BUSY={青年=[Employee [name=田七, age=12, salary=8888.88, Status=BUSY]], 老年=[Employee [name=李四, age=58, salary=5555.55, Status=BUSY]]}}
//分区
Map<Boolean,List<Employee>> map3=employees.stream()
.collect(Collectors.partitioningBy((e)->e.getSalary()>8000));
System.out.println(map3);//{false=[Employee [name=李四, age=58, salary=5555.55, Status=BUSY], Employee [name=王五, age=26, salary=3333.33, Status=VOCATION], Employee [name=赵六, age=36, salary=6666.66, Status=FREE]], true=[Employee [name=张三, age=18, salary=9999.99, Status=FREE], Employee [name=田七, age=12, salary=8888.88, Status=BUSY]]}
System.out.println("--------------------------------");
DoubleSummaryStatistics dss=employees.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(dss.getSum());
System.out.println(dss.getAverage());
System.out.println(dss.getMax());
System.out.println("--------------------------------");
String strr=employees.stream()
.map(Employee::getName)
.collect(Collectors.joining(","));
System.out.println(strr);//张三李四王五赵六田七
}