(inta) -> a * 2; // Calculate the double of aa -> a * 2; // or simply without type(a, b) -> a + b; // Sum of 2 parametersIf the lambda is more than one expression we can use { } and return
(x, y) -> {
intsum = x + y;
intavg = sum / 2;
returnavg;
}A lambda expression cannot stand alone in Java, it need to be associated to a functional interface.
interfaceMyMath {
intgetDoubleOf(inta);
}
MyMathd = a -> a * 2; // associated to the interfaced.getDoubleOf(4); // is 8All examples with "list" use :
List<String> list = [Bohr, Darwin, Galilei, Tesla, Einstein, Newton]sortsort(list, comparator)
list.sort((a, b) -> a.length() - b.length())
list.sort(Comparator.comparing(n -> n.length())); // samelist.sort(Comparator.comparing(String::length)); // same//> [Bohr, Tesla, Darwin, Newton, Galilei, Einstein]removeIf
list.removeIf(w -> w.length() < 6);
//> [Darwin, Galilei, Einstein, Newton]mergemerge(key, value, remappingFunction)
Map<String, String> names = newHashMap<>();
names.put("Albert", "Ein?");
names.put("Marie", "Curie");
names.put("Max", "Plank");
// Value "Albert" exists// {Marie=Curie, Max=Plank, Albert=Einstein}names.merge("Albert", "stein", (old, val) -> old.substring(0, 3) + val);
// Value "Newname" don't exists// {Marie=Curie, Newname=stein, Max=Plank, Albert=Einstein}names.merge("Newname", "stein", (old, val) -> old.substring(0, 3) + val);Allows to reference methods (and constructors) without executing them
// Lambda Form:getPrimes(numbers, a -> StaticMethod.isPrime(a));
// Method Reference:getPrimes(numbers, StaticMethod::isPrime);| Method Reference | Lambda Form |
|---|---|
StaticMethod::isPrime | n -> StaticMethod.isPrime(n) |
String::toUpperCase | (String w) -> w.toUpperCase() |
String::compareTo | (String s, String t) -> s.compareTo(t) |
System.out::println | x -> System.out.println(x) |
Double::new | n -> new Double(n) |
String[]::new | (int n) -> new String[n] |
Similar to collections, but
- They don't store their own data
- The data comes from elsewhere (collection, file, db, web, ...)
- immutable (produce new streams)
- lazy (only computes what is necessary !)
// Will compute just 3 "filter"Stream<String> longNames = list
.filter(n -> n.length() > 8)
.limit(3);Create a new stream
Stream<Integer> stream = Stream.of(1, 2, 3, 5, 7, 11);
Stream<String> stream = Stream.of("Jazz", "Blues", "Rock");
Stream<String> stream = Stream.of(myArray); // or from an arraylist.stream(); // or from a list// Infinit stream [0; inf[Stream<Integer> integers = Stream.iterate(0, n -> n + 1);Collecting results
// Collect into an array (::new is the constructor reference)String[] myArray = stream.toArray(String[]::new);
// Collect into a List or SetList<String> myList = stream.collect(Collectors.toList());
Set<String> mySet = stream.collect(Collectors.toSet());
// Collect into a StringStringstr = list.collect(Collectors.joining(", "));mapmap(mapper)
Applying a function to each element
// Apply "toLowerCase" for each elementres = stream.map(w -> w.toLowerCase());
res = stream.map(String::toLowerCase);
//> bohr darwin galilei tesla einstein newtonres = Stream.of(1,2,3,4,5).map(x -> x + 1);
//> 2 3 4 5 6filterfilter(predicate)
Retains elements that match the predicate
// Filter elements that begin with "E"res = stream.filter(n -> n.substring(0, 1).equals("E"));
//> Einsteinres = Stream.of(1,2,3,4,5).filter(x -> x < 3);
//> 1 2reduce
Reduce the elements to a single value
Stringreduced = stream
.reduce("", (acc, el) -> acc + "|" + el);
//> |Bohr|Darwin|Galilei|Tesla|Einstein|Newtonlimitlimit(maxSize)
The n first elements
res = stream.limit(3);
//> Bohr Darwin Galileiskip Discarding the first n elements
res = strem.skip(2); // skip Bohr and Darwin//> Galilei Tesla Einstein Newtondistinct Remove duplicated elemetns
res = Stream.of(1,0,0,1,0,1).distinct();
//> 1 0sorted Sort elements (must be Comparable)
res = stream.sorted();
//> Bohr Darwin Einstein Galilei Newton Tesla allMatch
// Check if there is a "e" in each elementsbooleanres = words.allMatch(n -> n.contains("e"));anyMatch: Check if there is a "e" in an element
noneMatch: Check if there is no "e" in elements
parallel Returns an equivalent stream that is parallel
findAny faster than findFirst on parallel streams
Wrappers (like Stream) are inefficients. It requires a lot of unboxing and boxing for each element. Better to use IntStream, DoubleStream, etc.
Creation
IntStreamstream = IntStream.of(1, 2, 3, 5, 7);
stream = IntStream.of(myArray); // from an arraystream = IntStream.range(5, 80); // range from 5 to 80Randomgen = newRandom();
IntStreamrand = gen(1, 9); // stream of randomsUse mapToX (mapToObj, mapToDouble, etc.) if the function yields Object, double, etc. values.
Collectors.groupingBy
// Groupe by lengthMap<Integer, List<String>> groups = stream
.collect(Collectors.groupingBy(w -> w.length()));
//> 4=[Bohr], 5=[Tesla], 6=[Darwin, Newton], ...Collectors.toSet
// Same as before but with Set
... Collectors.groupingBy(
w -> w.substring(0, 1), Collectors.toSet()) ...Collectors.counting Count the number of values in a group
Collectors.summing__summingInt, summingLong, summingDouble to sum group values
Collectors.averaging__averagingInt, averagingLong, ...
// Average length of each element of a groupCollectors.averagingInt(String::length)PS: Don't forget Optional (like Map<T, Optional<T>>) with some Collection methods (like Collectors.maxBy).
Creation
Stream<String> parStream = list.parallelStream();
Stream<String> parStream = Stream.of(myArray).parallel();unordered
Can speed up the limit or distinct
stream.parallelStream().unordered().distinct();PS: Work with the streams library. Eg. use filter(x -> x.length() < 9) instead of a forEach with an if.
In Java, it is common to use null to denote absence of result.
Problems when no checks: NullPointerException.
// Optional<String> contains a string or nothingOptional<String> res = stream
.filter(w -> w.length() > 10)
.findFirst();
// length of the value or "" if nothingintlength = res.orElse("").length();
// run the lambda if there is a valueres.ifPresent(v -> results.add(v));Return an Optional
Optional<Double> squareRoot(doublex) {
if (x >= 0) { returnOptional.of(Math.sqrt(x)); }
else { returnOptional.empty(); }
}Note on inferance limitations
interfacePair<A, B> {
Afirst();
Bsecond();
}A steam of type Stream<Pair<String, Long>> :
stream.sorted(Comparator.comparing(Pair::first)) // okstream.sorted(Comparator.comparing(Pair::first).thenComparing(Pair::second)) // dont work
Java cannot infer type for the .comparing(Pair::first) part and fallback to Object, on which Pair::first cannot be applied.
The required type for the whole expression cannot be propagated through the method call (.thenComparing) and used to infer type of the first part.
Type must be given explicitly.
stream.sorted(
Comparator.<Pair<String, Long>, String>comparing(Pair::first)
.thenComparing(Pair::second)
) // ok// Garde les mots plus grand que 20, grâce à la commande removeIf()
publicclassExercise
{
publicstaticvoidmain(String[] args) throwsIOException
{
List<String> words = Files.readAllLines(Paths.get("pays.txt"));
words.removeIf(obj -> obj.length() < 20);
System.out.println(words);
}
} List<String> words = Files.readAllLines(Paths.get("pays.txt")); // lit notre fichierwords.removeIf(w -> { inttaille = w.length();
Stringfirst = w.substring(0,1);
Stringlast = w.substring(taille-1, taille);
return !first.equalsIgnoreCase(last);
}
);publicclassIndex
{
publicstaticvoidmain(String[] args) throwsIOException
{
Scannerin = newScanner(System.in);
Map<String, String> index = newTreeMap<>();
intline = 0;
while (in.hasNextLine())
{
line++;
for (Stringword : in.nextLine().split("[^'\\pL]+"))
{
//we merge word into a map with the line in first and then//we take the old value and we add to it the new val value//like this we can keep a trace of old value and add new onesindex.merge(word, Integer.toString(line), (old, val)-> old + ", " + val);
}
}
System.out.println(index);
}
}Map<String, Set<Integer>> index = newTreeMap<>();
//nous devons donc faire en sorte que Index soit une Map de String, Set<Integer>index.merge(word, newTreeSet<>(Arrays.asList(line)), (old, next) -> { old.addAll(next);
returnold;
});classWords
{ //static method to access it from the class namepublicstaticintvowels(Stringw)
{
returnw.length() - w.toLowerCase().replaceAll("[aâàäæeéêèëiîïoôœöuûùüyÿ]", "").length();
}
}
publicclassExercise
{
publicstaticvoidmain(String[] args) throwsIOException
{
List<String> words = Files.readAllLines(Paths.get("pays.txt"));
Collections.sort(words, Comparator.comparing(Words::vowels).thenComparing(String::compareTo));
System.out.println(words);
}
}classCollections {
publicstatic <T> T[] toArray(Collection<T> coll, Function<Integer, T[]> constructor)
{
T[] result = constructor.apply(coll.size());
Iterator<T> iter = coll.iterator();
for (inti = 0; i < result.length; i++)
result[i] = iter.next();
returnresult;
}
}
publicclassExercise
{
publicstaticvoidmain(String[] args) throwsIOException
{
List<String> words = Files.readAllLines(Paths.get("pays.txt"));
String[] wordArray = Collections.toArray(words, String[]::new); //create new array of stringsArrays.sort(wordArray);
for (inti = 0; i < 10; i++)
System.out.println(wordArray[i].toUpperCase());
// Note: If wordArray was an Object[], you couldn't call // wordArray[i].toUpperCase().
}
}// TODO: Make this method receive and return an array.// Accept a constructor expression for constructing the // returned array.// Function<T, R> { R apply(T args); }publicclassUtil
{
//First parameter of Function<What apply will take, What apply will return>//La Function prend un int en paramètre et retournera un nouveau tableau de T[]//Here we want apply to take the size of the String[] and to return a new T [] arraypublicstatic <T> T[] filter(T[] values, Predicate<T> p, Function<Integer, T[]> f)
{
List<T> result = newArrayList<>();
for (Tvalue : values)
{
//predicate test value and add it if it's trueif (p.test(value)) { result.add(value); }
}
//on retourne un array de string et on lui passe la taillereturnresult.toArray(f.apply(result.size()));
}
}
//Call of the methodString[] wordsWithA = Util.filter(words, w -> w.contains("a"), String[]::new);
//Way to display an arraySystem.out.println(Arrays.toString(wordsWithA));publicclassWords
{
publicstaticlongdistinctVowels(Stringstr)
{
returnStream.of(str.split("")) //on découpe chaque lettres//on prend un lettre et on lui enlève ses accents //normalize retourne un tableau pour à [a,`]
.map(c -> Normalizer.normalize(c,Normalizer.Form.NFD)
.substring(0,1))
//on filtre notre lettre pour savoir si elle fait partie des//voyelles
.filter(s -> "aeiou".contains(s))
.distinct() //on prend chaque valeur 1 fois si identique
.count(); //on compte
}
}publicclassStreams
{
publicstaticvoidmain(String[] args) throwsIOException
{
Scannerin = newScanner(System.in);
Stringfilename = in.next();
try (Stream<String> lineStream = Files.lines(Paths.get(filename))){
//Ici on retourne le nombre de mot avec 5 voyelleslongcount = lineStream
.filter(s -> Words.distinctVowels(s) == 5)
.count();
System.out.println(count + " words with 5 distinct vowels"); } try (Stream<String> lineStream = Files.lines(Paths.get(filename))){
//On souhaite récupérer une liste de string depuis le Stream lineStream//on filtre les mots ayant 5 voyelles distinctesList<String> result = lineStream.filter(s -> Words.distinctVowels(s) == 5)
//on trie grace a sorted(Comparator.comparing( Fonction de tri )) //Ici par la longueur (String::length)
.sorted(Comparator.comparing(String::length))
//on limite au 20 premier résultat
.limit(20)
//on collect (Collectors) En toList toArray .. etc
.collect(Collectors.toList());
System.out.println(result);
} }
}publicclassStreams
{
List<Pair<String, Long>> wordsWithManyVowels(Stream<String> words, intn)
{
returnwords
.map(w -> Pair.of(w, (Words.vowels(w) - (w.length() - Words.vowels(w)))))
.sorted(
Comparator.comparingLong((Pair<String,Long> p) -> -p.second())
.thenComparing((Pair<String,Long> p) -> p.first()))
.limit(n)
.collect(Collectors.toList());
}
}//Exemples avec des collections//opening est une List<String>Collections.max(opening, (s,t) -> s.length() - t.length());
Collections.max(opening,Comparator.comparing(String::length));//list = (0, 44 , 33) retourne e0,e44,o33publicStringgetString(List<Integer> list) {
returnlist.stream()
.map(n -> n % 2 == 0 ? "e" + n : "o" + n)
//joining retourne une string séparé par ici une virgule
.collect(Collectors.joining(",")); }//opening est une liste de string//LambdaCollections.max(opening, (s,t) -> s.length() - t.length());
//CompartorCollections.max(opening,Comparator.comparing(String::length));
//Compartor Streamopening.stream()
.sorted(Comparator.comparing(String::length).reversed())
.findFirst().get(); //get retourne un stringopening.stream()
.filter(Predicates.greater(String::length,5)) //we pass string.length to func
.distinct()
.toArray(String[]::new);
//L'interface PredicatesinterfacePredicates{ //func will take a T and an Integer//here T is a String and Integer = to the String.length()publicstatic <T> Predicate<T> greater(Function<T,Integer> func, intn){
//so func.apply(p) will return the length of p (a string)//A predicate is a lamba that return true or falsereturnp -> func.apply(p) > n; }
}
System.out.println(Arrays.toString(array));
//----Same without predicates interfacearray = opening.stream().filter(s -> s.length() > 5).distinct().toArray(String[]::new);List<Pair<Integer, Integer>> triangles = Streams.triangular(7) //limite a 7
.collect(Collectors.toList());
//we need a method that construct the triangular streaminterfaceStreams{
publicstaticStream<Pair<Integer, Integer>> triangular(intmax){
returnStream.iterate(Pair.of(1,1), //Iterate prend une valeur de départ//en second parametre prend les itérations à faire
(Pair<Integer, Integer> p) -> Pair.of(p.first() + 1, (p.second() -1 ) + p.fist()))
.limit(max);
}
}System.out.println(list.stream()
.filter((Pair<String, Integer> p) -> p.second() % 2 == 0)
.sorted(Comparator.comparing(Pair::second))
.map(Pair::first)
.collect(Collectors.toList())
);
System.out.println("-- 5. Sorted even values names");
System.out.println(list.stream()
.filter((Pair<String, Integer> p) -> p.second() % 2 == 0)
.sorted(Comparator.comparing((Pair<String, Integer> p) -> p.second()))
.map((Pair<String,Integer> p) -> p.first())
.collect(Collectors.toList()));publicclassFilterable{
publicstatic <T> List<T> filter(List<T> mylist, Predicate<T> predicate){
List<T> list = newArrayList<>();
for(Tval: mylist){
if(predicate.test(val)){ list.add(val);}
}
returnlist;
}
}
List<Dragon> oldest = Filterable.filter(dragons, d -> d.color() == Dragon.Color.Red && d.age() >= 4000);list.stream()
.mapToInt(i -> i) //lambda basique
.average()
.getAsDouble();
collectionKids.stream()
.mapToInt(t -> t.age) //toujours fournir une lambda
.summaryStatistics() //.getCount() .getMax() .getSum()
.getAverage();List.
forEach(Iterables)
//ne marche pas sur Array.asList//faire List<String> str2 = new ArrayList<String>(str1);//removeIf mettre l'inverse de ce que l'on souhaiteremoveIf(Collections) replaceAll()
sort()
Map.
forEach()
computeIfAbsent()
merge()
replaceAll()interfacePredicates{
publicstatic <T> Predicate<T> greater(Function<T, Integer> f, intn) {
returnp -> f.apply(p) > n;
}
}
//Interface Streams mais la méthode retourne un streaminterfaceStreams{
publicstaticStream<Pair<Integer,Integer>> triangular(intmax){
returnStream.iterate(
//Graine (valeur de départ)Pair.of(1,1), //Calcul des valeurs suivantes
(Pair<Integer,Integer> p) -> Pair.of(p.first() + 1, (p.second()-1) + p.first())).limit(max);
}
}//Accumulator sum, lambdaAccumulator.accumulate(list, 0, (r, n) -> r + n.second()));
//on definit un interface et une méthode static accumulate qui prendr une liste de Pair<T, Integer> //un int de départ//une FunctionAcc ou T = Pair<T, Integer> en entree et R (retour) retournera un Integer en sortieinterfaceAccumulator{
publicstatic <T> intaccumulate(List<T> list, intinit, FunctionAcc<T, Integer> f ){
intsum = init;
for (inti = 0; i < list.size(); i++){
sum = f.apply(sum, list.get(i));
}
returnsum;
}
}
interfaceFunctionAcc<T,R>{
//doit être redéfinieRapply(intinit, Targ);
}
// # 1 il faut redéfinir la fonction apply de notre FunctionAcc anonymeintsum = Accumulator.accumulate(list, 0, newFunctionAccumulateur<Pair<String, Integer>, Integer>() {
@OverridepublicIntegerapply(intinit, Pair<String, Integer> arg) {
returninit + arg.second();
}
});
//# 2 ou ecrire notre Function en dehors et la passe a l'accumulatorFunctionAccumulateur<Pair<String, Integer>, Integer> f = newFunctionAccumulateur<Pair<String, Integer>, Integer>() {
@OverridepublicIntegerapply(intinit, Pair<String, Integer> pair) {
returninit + pair.second();
}
};
//Ici on passe notre fonction à l'AccumulatorSystem.out.println(
Accumulator.accumulate(list,0 , f)
);//Sans Compartor, Streams ou Collections retourne les plus vieux DragonspublicclassFilterable
{
publicstatic <T> List<T> filter(List<T> list, Predicate<T>p)
{
// version one-liner, qui ne respecte pas la consigne (pas de Stream ni Collectors)// return list.stream().filter(p).collect(Collectors.toList());// version nettement plus moche, qui respecte la consigne.List<T> copy = newLinkedList<T>();
copy.addAll(list);
copy.removeIf(p.negate()); //on enlève si ca ne respecte pas le predicatereturncopy;
}
}This cheat sheet was based on the lecture of Cay Horstmann http://horstmann.com/heig-vd/spring2015/poo/