Java 13はすべて来て、あなたはまだJava 8の新しい(古い)特性を理解していませんか?
28931 ワード
Javaの現在のバージョンの反復速度はあまり速くないので、うっかりして、いくつかのバージョンを逃してしまいました.公式バージョンはJava 12に更新されていますが、現在のところ、多くのJavaシステムはJava 8上で実行されており、残りの一部の歴史的遺留システムはJava 7、さらにはJava 6上で走っています.私がJavaを習ったばかりの頃は、ちょうどJava 7のバージョンの末期で、その時すでにJava 8の新しい特性に関する噂がたくさんありましたが、当時は初心者としてはあまり注目されていませんでしたが、「lambda式」や「関数式プログラミング」などをぼんやり覚えていて、その真意もよく分かりませんでした.本当にJava 8を大量に応用したのは、私が仕事をしてから1年後のことかもしれませんが、IBMフォーラムの文章から始まったことを覚えています.
先日、ある大学の同級生と話していたとき、彼らの会社のいくつかの問題について話しました.彼らのシステムはJDK 7のバージョンに基づいており、ほとんどの従業員はバージョンをアップグレードしたくないので、Java 8の新しい特性を受け入れたくないからです.私はとても驚いて、Java 13に近づいています.Java 8の新しい(古い)特性を知りたくありませんか.そこでこの文章では,Java 8のlambdaとstreamに関する新しい(古い)特性を分かりやすいコードと結びつけて紹介し,関数式プログラミングの考え方を体得する.
Lambda式
lambda式は匿名の内部類のより簡潔な文法糖であると簡単に考えることができる.次の2つのスレッドの作成方法を見て、直感的に感じてみましょう.
Lambda式を上手に使うには、まず関数式インタフェースを理解する必要があります.では、関数式インタフェースとは何ですか.まず、
Lambda式は、インタフェースを実装する方法パラメータ、戻り値、コード行数などによって、いくつかの異なる書き方があります.パラメータなし 単一パラメータの 複数のパラメータの コードが1行しかない場合は、括弧 を省略できます.には、戻り値の がある.
lambda式は匿名の内部クラスと同様にfinal修飾の外部のリソースしか参照できないことに注意してください.Java 8に表示されない宣言変数はfinalですが、lambda式の内部では修正できません.
Lambda式にはもっと簡単な書き方がありますが、次のコードを見て、この
上の例を拡張して、下のコードを見て、関数式プログラミングの思想を体得します.関数をパラメータとして,
内蔵関数インタフェース
Java 8には多くの関数インタフェースが内蔵されており、すべて戻り値なし、パラメータ付き 戻り値がある、パラメータがない 戻り値がある、パラメータがある はboolean、パラメータのある と見なすことができる.
集合クラスのStream
Java 8は、集合フレームワークにフロー処理機能を追加し、集合データを容易に処理する方法を提供しています.Streamは、中間動作と端末動作の2つの動作に大きく分けることができ、ここでは中間動作状態の問題は考慮されない.中間操作は複数あってもよいが、端末操作は1つしかない.中間操作は一般的に、中間操作を追加するとすぐに有効にならない対流要素の追加操作であり、終端操作が追加されると、ストリーム全体が開始されます.また、ストリームは多重化できず、ストリームが起動すると、このストリームに端末操作を付加することはできません.
Streamの作成方法
ストリームの作成方法は、次のとおりです.
中間操作
sparkやflinkに詳しいと、中間操作は実はspark、flinkの演算子と同じで、ネーミングも同じで、ストリームが中間操作を呼び出す方法は、すぐにこの操作を実行することはなく、端末操作を呼び出すまで待ってから実行されることがわかります.次の例では filterオペレーション、パラメータはPredicateであり、このオペレーションはデータストリームの断言結果がfalseであるすべての要素 をフィルタリングする. map操作、パラメータはFunctionで、この操作はデータストリームの中の要素をすべて新しい要素に処理し、mapToInt、mapToLong、mapToDoubleとmapは に似ている. flatMapオペレーション.パラメータはFunctionですが、Functionの戻り値はStreamです.このオペレーションはmapと同様に各エレメントを処理します.mapは現在のストリームの1つのエレメントを別のエレメントに処理しますが、flatMapは現在のストリームの1つのエレメントを複数のエレメントに処理します.flatMapToInt、flatMapToDouble、flatMapToLong、flatMapと似ています. peek操作、パラメータはConsumerで、変更操作は各要素を処理しますが、新しいオブジェクトは戻りません. distinct操作は、各要素の sorted操作です.これはソート操作であることは明らかです.パラメータのないsortedを使用すると、要素は limit操作、パラメータは非負のlongタイプ整数であり、この操作はストリームの最初のn要素を切り取り、パラメータnがストリームの長さより大きい場合、何もしていないことに相当する. skip操作で、パラメータは非負のlongタイプ整数であり、この操作はストリームの最初のn要素をスキップし、パラメータnがストリームの長さより大きい場合、すべての要素をスキップします.
ターミナルオペレーション
各ストリームには1つの端末操作しかありません.端末操作方法を呼び出すと、ストリームは本当に中間操作を実行し始め、複数の中間操作の処理を経て、最終的には端末操作で1つの結果を生成します. forEach操作、パラメータはConsumerで、これは簡単な遍歴操作に相当し、処理されたストリームの各要素を遍歴します. toArray動作は、上述のように、中間動作の処理結果に基づいて、新たな配列 を生成する動作である. allMatch、anyMatch、noneMatch操作は、クエリ に一致するPredicateを受信する. findFirst、findAny操作は、いずれもストリームの要素を返し、戻り値は reduceは比較的複雑な操作であり、単一パラメータ、二重パラメータ、三パラメータの3つのリロード方法がある.主に積算演算に用いられるもので、どのリロード方法でも二重パラメータのBiFunctionを提供する必要があります.このBiFunctionの最初のパラメータは前のすべての要素の積算値を表し、2番目のパラメータは現在の要素の値を表し、いくつかの例を見てみましょう. max、min、countの3つの操作はいずれも比較的簡単で、それぞれストリーム中の最大値、最小値、要素個数 を返す. collect操作、この操作はtoArrayに似ていますが、ここではストリームをCollectionまたはMapに変換します.一般的にこの操作はCollectorsツールクラスと組み合わせて使用されます.次の簡単な例を見てください. です.
単語統計のケース
最後に、上記の操作を組み合わせて、単語統計の例を通じて、フロー処理のメリットをより直感的に感じさせます.
残念ながらJava 8のStreamではグループ化や集約操作はサポートされていないので、ここではtoMapメソッドを使用して単語の数を統計しています.
Java 8の集合クラスはparallelStreamメソッドを提供してパラレルストリーム(最下位はForkJoinベース)を取得します.一般的には推奨されませんが、データ規模が小さい場合はパラレルストリームを使用するよりもシリアルを使用するほうが効率的ではありません.データ規模が大きい場合、シングルマシンの計算能力は限られています.分散計算には、より強力なsparkまたはflinkを使用することをお勧めします.
これでJava 8はlambdaとStreamの特性について分析を終えた.もちろんJava 8は古典的なバージョンとして、それだけではないに違いない.Doug Leaの大物の共同発注もJava 8バージョンで多くの内容を更新し、より多彩な同時ツールを提供し、新しいtimeパッケージなどを提供し、これらは新しい話題として議論することができる.その後の文章では引き続き関連内容を共有できることを期待しています.
オリジナルは容易ではありません.転載は出典を明記してください.www.yangxf.top/
転載先:https://juejin.im/post/5ca55d3251882544136e97dc
先日、ある大学の同級生と話していたとき、彼らの会社のいくつかの問題について話しました.彼らのシステムはJDK 7のバージョンに基づいており、ほとんどの従業員はバージョンをアップグレードしたくないので、Java 8の新しい特性を受け入れたくないからです.私はとても驚いて、Java 13に近づいています.Java 8の新しい(古い)特性を知りたくありませんか.そこでこの文章では,Java 8のlambdaとstreamに関する新しい(古い)特性を分かりやすいコードと結びつけて紹介し,関数式プログラミングの考え方を体得する.
Lambda式
lambda式は匿名の内部類のより簡潔な文法糖であると簡単に考えることができる.次の2つのスレッドの作成方法を見て、直感的に感じてみましょう.
//
new Thread(new Runnable() {
@Override
public void run() {
// ...
}
}).start();
// lambda
new Thread(() -> {
// ...
}).start();
Lambda式を上手に使うには、まず関数式インタフェースを理解する必要があります.では、関数式インタフェースとは何ですか.まず、
interface
によって修飾されたインタフェースでなければならない.次に、インタフェースには、実装されるべき方法が1つしかない.関数インタフェースと一般インタフェースを区別する簡単な方法があります.それは、インタフェースに@FunctionalInterface
注釈を追加し、エラーを報告しなければ、関数インタフェースであり、匿名の内部クラスの代わりにlambda式を使用することができます.次の例を見ると、AとBは関数式インタフェースであり、Cには抽象的な方法がなく、Dはインタフェースではないので、lambda式は使用できないことが明らかになった.//
interface A {
void test();
}
//
interface B {
default void def() {
// balabala...
}
void test();
}
//
interface C {
default void def() {}
}
//
abstract class D {
public abstract void test();
}
Lambda式は、インタフェースを実装する方法パラメータ、戻り値、コード行数などによって、いくつかの異なる書き方があります.
interface A {
void test();
}
A a = () -> {
// ...
};
interface B {
void test(String arg);
}
B b = arg -> {
// ...
};
interface C {
void test(String arg1, String arg2);
}
C c = (a1, a2) -> {
// ...
};
interface D {
void test(String arg1, String arg2, String arg3);
}
D d = (a1, a2, a3) -> {
// ...
};
interface B {
void test(String arg);
}
B b = arg -> System.out.println("hello " + arg);
interface E {
String get(int arg);
}
E e = arg -> {
int r = arg * arg;
return String.valueOf(r);
};
// return
e = arg -> String.valueOf(arg * arg);
lambda式は匿名の内部クラスと同様にfinal修飾の外部のリソースしか参照できないことに注意してください.Java 8に表示されない宣言変数はfinalですが、lambda式の内部では修正できません.
int i = 0;
A a = () -> {
i++; //
// ...
};
Lambda式にはもっと簡単な書き方がありますが、次のコードを見て、この
::
記号はよく知られていますか?やはりCシステムの影響から離れられないのでしょうか?class Math {
int max(int x, int y) {
return x < y ? y : x;
}
static int sum(int x, int y) {
return x + y;
}
}
interface Computer {
int eval(int arg1, int arg2);
}
//
Computer sumFun = Math::sum;
//
sumFun = (x, y) -> x + y;
Math math = new Math();
//
Computer maxFun = math::max;
//
maxFun = (x, y) -> x < y ? y : x;
int sum = sumFun.eval(1, 2);
int max = maxFun.eval(2, 3);
上の例を拡張して、下のコードを見て、関数式プログラミングの思想を体得します.関数をパラメータとして,
compute
メソッドを実際に呼び出したときに,どのような演算を行うべきかを決定した.class Biz {
int x, y;
Biz(int x, int y) {
this.x = x;
this.y = y;
}
int compute(Computer cpt) {
// ...
return cpt.eval(x, y);
}
}
Biz biz = new Biz(1, 2);
int result = biz.compute((x, y) -> x * y);
result = biz.compute(Math::sum);
内蔵関数インタフェース
Java 8には多くの関数インタフェースが内蔵されており、すべて
java.util.function
パッケージの下に置かれています.これらのインタフェースは日常開発の大部分のニーズを満たすことができます.これらの関数インタフェースは主に以下のように分類されています.Consumer
タイプConsumer consumer = str -> {
// ...
};
BiConsumer biConsumer = (left, right) -> {
// ...
};
Supplier
タイプSupplier supplier = () -> {
// ...
return "hello word";
};
Function
型Function function = i -> {
// ...
return "hello word " + i;
};
BiFunction biFunction = (m, n) -> {
int s = m + n;
return "sum = " + s;
};
Predicate
タイプを返し、Function
の特例Predicate predicate = str -> {
// ...
return str.charAt(0) == 'a';
};
BiPredicate biPredicate = (left, right) -> {
// ...
return left.charAt(0) == right.charAt(0);
};
集合クラスのStream
Java 8は、集合フレームワークにフロー処理機能を追加し、集合データを容易に処理する方法を提供しています.Streamは、中間動作と端末動作の2つの動作に大きく分けることができ、ここでは中間動作状態の問題は考慮されない.中間操作は複数あってもよいが、端末操作は1つしかない.中間操作は一般的に、中間操作を追加するとすぐに有効にならない対流要素の追加操作であり、終端操作が追加されると、ストリーム全体が開始されます.また、ストリームは多重化できず、ストリームが起動すると、このストリームに端末操作を付加することはできません.
Streamの作成方法
ストリームの作成方法は、次のとおりです.
String[] array =
Stream stream;
// 1. Stream builder
stream = Stream.builder()
.add("1")
.add("2")
.build();
// 2. Stream.of ,
stream = Stream.of("1", "2", "3");
// 3. Collection stream ,
Collection list = Arrays.asList("1", "2", "3");
stream = list.stream();
// 4. IntStream、LongStream、DoubleStream
IntStream intStream = IntStream.of(1, 2, 3);
LongStream longStream = LongStream.range(0L, 10L);
DoubleStream doubleStream = DoubleStream.of(1d, 2d, 3d);
// 5. StreamSupport
stream = StreamSupport.stream(list.spliterator(), false);
中間操作
sparkやflinkに詳しいと、中間操作は実はspark、flinkの演算子と同じで、ネーミングも同じで、ストリームが中間操作を呼び出す方法は、すぐにこの操作を実行することはなく、端末操作を呼び出すまで待ってから実行されることがわかります.次の例では
toArray
の端末操作が追加されています.ストリームを配列に変換します.// 1
// array = [2, 3]
Integer[] array = Stream.of(1, 2, 3)
.filter(i -> i > 1)
.toArray(Integer[]::new);
// 10
// array = [11, 12, 13]
Integer[] array = Stream.of(1, 2, 3)
.map(i -> i + 10)
.toArray(Integer[]::new);
// "," , Stream
// array = ["1", "2", "3", "4", "5", "6"]
String[] array = Stream.of("1", "2,3", "4,5,6")
.flatMap(s -> {
String[] split = s.split(",");
return Stream.of(split);
})
.toArray(String[]::new);
Stream.of(new User("James", 40), new User("Kobe", 45), new User("Durante", 35))
.peek(user -> {
user.name += " NBA";
user.age++;
}).forEach(System.out::println);
// User(name=James NBA, age=41)
// User(name=Kobe NBA, age=46)
// User(name=Durante NBA, age=36)
equals
方法に従って重量を除去することが明らかである.// array = [hello, hi]
String[] array = Stream.of("hello", "hi", "hello")
.distinct()
.toArray(String[]::new);
Comparable
タイプに変換され、変換できないと異常が放出されます.また、比較器Comparator
に入力し、比較器の比較結果に従ってソートすることもできる.//
// sorted = [hi, haha, hello]
String[] sorted = Stream.of("hello", "hi", "haha")
.sorted(Comparator.comparingInt(String::length))
.toArray(String[]::new);
//
// array = [hello, hi, haha]
String[] array = Stream.of("hello", "hi", "haha", "heheda")
.limit(3)
.toArray(String[]::new);
//
// array = [haha, heheda]
String[] array = Stream.of("hello", "hi", "haha", "heheda")
.skip(2)
.toArray(String[]::new);
ターミナルオペレーション
各ストリームには1つの端末操作しかありません.端末操作方法を呼び出すと、ストリームは本当に中間操作を実行し始め、複数の中間操作の処理を経て、最終的には端末操作で1つの結果を生成します.
Stream.of("hello", "hi", "haha", "heheda")
.limit(0)
.forEach(s -> System.out.println(">>> " + s));
// array = [hello, hi, haha, heheda]
Object[] array = Stream.of("hello", "hi", "haha", "heheda")
.toArray();
// b = false
boolean b = Stream.of("hello", "hi", "haha", "heheda")
.allMatch(s -> s.equals("hello"));
// b = true
b = Stream.of("hello", "hi", "haha", "heheda")
.anyMatch(s -> s.equals("hello"));
// b = true
b = Stream.of("hello", "hi", "haha", "heheda")
.noneMatch(s -> s.equals("nihao"));
Optional
で包装されます.String first = Stream.of("hello", "hi", "haha", "heheda")
.findFirst().get();
first = Stream.of("hello", "hi", "haha", "heheda")
.findAny().get();
//
// reduceS ="hello ; hi ; haha ; heheda"
String reduceS = Stream.of("hello", "hi", "haha", "heheda")
.reduce((x, y) -> x + " ; " + y)
.get();
//
// lenght = 17
int length = Stream.of("hello", "hi", "haha", "heheda")
.map(String::length)
.reduce(0, (x, y) -> x + y);
// , , ,
int reduce = Stream.of("hello", "hi", "haha", "heheda")
.reduce(0, (x, y) -> x + y.length(), (m, n) -> m + n);
// max = "heheda"
String max = Stream.of("hello", "hi", "haha", "heheda")
.max(Comparator.comparingInt(String::length))
.get();
// min = "hi"
String min = Stream.of("hello", "hi", "haha", "heheda")
.min(Comparator.comparingInt(String::length))
.get();
// count = 4
long count = Stream.of("hello", "hi", "haha", "heheda")
.count();
// List [hello, hehe, hehe, hi, hi, hi]
List list = Stream.of("hello", "hehe", "hehe", "hi", "hi", "hi")
.collect(Collectors.toList());
// Set [hi, hehe, hello]
Set set = Stream.of("hello", "hehe", "hehe", "hi", "hi", "hi")
.collect(Collectors.toSet());
// , Map,map key ,value
// map = {hi=3, hehe=2, hello=1}
Map map = Stream.of("hello", "hehe", "hehe", "hi", "hi", "hi")
.collect(Collectors.toMap(s -> {
// map key
return s;
}, s -> {
// 1 map value
return 1;
}, (x, y) -> {
// key
return x + y;
}, () -> {
// Map
return new LinkedHashMap<>();
}));
単語統計のケース
最後に、上記の操作を組み合わせて、単語統計の例を通じて、フロー処理のメリットをより直感的に感じさせます.
Path path = Paths.get("/Users/.../test.txt");
List lines = Files.readAllLines(path);
lines.stream()
.flatMap(line -> {
String[] array = line.split("\\s+");
return Stream.of(array);
})
.filter(w -> !w.isEmpty())
.sorted()
.collect(Collectors.toMap(w -> w, w -> 1,
(x, y) -> x + y,
LinkedHashMap::new))
.forEach((k, v) -> System.out.println(k + " : " + v));
残念ながらJava 8のStreamではグループ化や集約操作はサポートされていないので、ここではtoMapメソッドを使用して単語の数を統計しています.
Java 8の集合クラスはparallelStreamメソッドを提供してパラレルストリーム(最下位はForkJoinベース)を取得します.一般的には推奨されませんが、データ規模が小さい場合はパラレルストリームを使用するよりもシリアルを使用するほうが効率的ではありません.データ規模が大きい場合、シングルマシンの計算能力は限られています.分散計算には、より強力なsparkまたはflinkを使用することをお勧めします.
これでJava 8はlambdaとStreamの特性について分析を終えた.もちろんJava 8は古典的なバージョンとして、それだけではないに違いない.Doug Leaの大物の共同発注もJava 8バージョンで多くの内容を更新し、より多彩な同時ツールを提供し、新しいtimeパッケージなどを提供し、これらは新しい話題として議論することができる.その後の文章では引き続き関連内容を共有できることを期待しています.
オリジナルは容易ではありません.転載は出典を明記してください.www.yangxf.top/
転載先:https://juejin.im/post/5ca55d3251882544136e97dc