public class Computer {
private Optional<Soundcard> soundcard;
public Optional<Soundcard> getSoundcard() { ... }
...
}
String name = computer.flatMap(Computer::getSoundcard)
.flatMap(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
new features in java
cat file1 file2 | tr "[A-Z]" "[a-z]" | sort | tail -3
since we have used tail lets talk about it for some time
tail -F filename is used to tail logs in realtime. eg as logs are built the tail command shows them
tail -f or --follow is used to tail logs based on file descriptor..even if file is renamed it will continue to log since it is via file descriptor.Hence if logs are written by system you can do tail -f
but to follow a file with filename use tail -F filename
which is mostly used
We say that sort takes a stream of lines[3] as input and produces another stream of lines as output
Java 8 adds a Streams API (note the uppercase S) in java.util.stream based on this idea; Stream<T>
is a sequence of items of type T. You can think of it as a fancy iterator for now.
The key motivation for this is that you can now program in Java 8 at a higher level of abstraction, structuring your thoughts of turning a stream of this into a stream of that
Java 8 can transparently run your pipeline of Stream operations on several CPU cores on disjoint parts. parallelism for free without threads
Files[] hiddenFiles = new File(".").listFiles(new FileFilter(){
public boolean accept(File file){
return file.isHidden();
}
});
lets talk a little about anonymous class
FileFilter f = new Filter(){
public boolean accept(File file){
return file.isHidden();
}
};
public static boolean isGreenApple(Apple apple){
return "green".equals(apple.getColor());
}
static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> p){
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if(p.test(apple){
result.add(apple)
}
}
}
filterApples(inventory, (Apple a) -> "green.equals(a.getcolor()));
or
filterApples(inventory, (Apple a) -> a.getWeight() > 150);
Map<Currency, List<Transaction>> transactionsByCurrencies = new HashMap<>(); //we have to group the transactions in this map w,r,t currencies
for(Transaction transaction: transactions) {
if(transaction.getPrice() > 1000) {
Currency currency = transaction.getCurrency();
List<Transactions> transactionForCurrency = transactionsByCurrencies.get(currency);
if(transactionsforCurrency == null) {
//add it in array list of transactionsByCurrencies
}
transactionsForCurrency.add(transaction);
}
}
Map<Currency, List<Transaction>> transactionsByCurrencies = transactions.stream().filter((Transaction t) --> t.getPrice() > 1000).collect(groupingBy(Transaction::getCurrency));
List<Apple> heavyApples = inventory.stream().filter((....blah)
Diamond Problem
If B and C inherit from A and D inherits B and C (multiple inheritance) it forma a diamond
A
B C
D
if B and C overrides method from A. Which method will D receive?
so in java 8 if A B and C are interfaces B and C can provide different default implementation of an abstract method in A. Hence D dosent know which one to take?. So to mitigate this D should reimplimet the method or compile error is thrown
IN JAVA 7
Collections.sort(dishArrayListVariable , new Comparator{
public int compare(Dish d1, Dish d2){
return Integer.compare(d1.getCalories(), d2.getCalories())
}
}
IN JAVA 8
Node d is a dish
List<String> lowCalorificDishes =
menu.stream()
.filter(d -> d.getCalories() < 400) //select
.sorted(comparing(Dish::getCalories)) //comparator
.map(Dish::getName) //extract names
.collect(toList()) //convert to list
Map<Dish.Type, List<Dish>> dishesByType =
menu.stream().collect(groupingBy(Dish::getType));
Map may contain
{FISH=[prawns, salmon],
OTHER=[french fries, rice, season fruit, pizza],
MEAT=[pork, beef, chicken]}
DEFINITION OF STREAMS
many stream operations return stream themselves allowing pipelining. like unix pipes
filter: takes lambda to exclude certain elements
map: takes lambda to transform an element into another. eg .map(Dish::getName) //extract names
limit: truncates a stream to contain no more than given elements
collect: converts a stream into another form
TRAVERSABLE ONLY ONCE ** a stream is only traversable once. After its consumed it cannot be traversed again**
** INTERNAL TRAVERSAL TO OPTIMIZE** streams have internal iteration. This enables them to manage the parallelism and order of doing things.in a foreach we will specify an order of iterating and doing things
List<String> dishNames = menu.stream()
.map(Dish::getName)
.collect(toList());
words.stream()
.map(word -> word.split(""))
.distinct()
.collect(toList());
Stream<String>
so the thing inside map should return a Stringwords.stream()
.map(word -> word.split(""))
.map(Arrays::stream)
.distinct()
.collect(toList());
words.stream()
.map(word -> word.split(""))
.flatMap(Arrays::stream)
.distinct()
.collect(toList());
stream<String>
and not stream<String[]>
List<Integer> numbers1 = Arrays.asList(1, 2, 3);
List<Integer> numbers2 = Arrays.asList(3, 4);
List<int[]> pairs =
numbers1.stream()
.flatMap(i -> numbers2.stream()
.map(j -> new int[]{i, j})
)
.collect(toList());
above converts every integer in the stream to a pair
every number in stream i is converted to a stream
and then this gives us a Stream.
now flatmap is going to use the value in the stream which is the integer in numbers1
and it converts that into a pair int[]{i,j}
divisible by 3
numbers1.stream()
.flatMap(i ->
numbers2.stream()
.filter(j -> (i + j) % 3 == 0)
.map(j -> new int[]{i, j})
)
.collect(toList());
if(menu.stream().anyMatch(Dish::isVegetarian)){
System.out.println("The menu is (somewhat) vegetarian friendly!!");
}
boolean isHealthy = menu.stream()
.allMatch(d -> d.getCalories() < 1000);
boolean isHealthy = menu.stream()
.noneMatch(d -> d.getCalories() >= 1000);
Optional<Dish> dish =
menu.stream()
.filter(Dish::isVegetarian)
.findAny();
List<Integer> someNumbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> firstSquareDivisibleByThree =
someNumbers.stream()
.map(x -> x * x)
.filter(x -> x % 3 == 0)
.findFirst(); // 9
int sum = 0;
for (int x : numbers) {
sum += x;
}
In above code we have sum=0 and sum = sum+x
in java 8
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
reduce takes 2 arguments
0 which is the initial value
BinaryOperator combines 2 elements and produces new value
the lambda combines each element repeatedly until it is reduced to a single value
int sum = numbers.stream().reduce(0, Integer::sum);
Optional<Integer> sum = numbers.stream().reduce((a, b) -> (a + b));
since initial value is not set Optional is returned for the case where stream is null
we can also compute maxima and minima using reduction
Optional<Integer> max = numbers.stream().reduce(Integer::max);
counting number of elements in a stream using map and reduce
int count = menu.stream()
.map(d -> 1)
.reduce(0, (a, b) -> a + b);
long count = menu.stream().count();
int sum = numbers.parallelStream().reduce(0, Integer::sum);
Stateful Operations
By contrast, some operations such as sorted or distinct seem at first to behave like filter or map—all take a stream and produce another stream (an intermediate operation), but there’s a crucial difference. Both sorting and removing duplicates from a stream require knowing the previous history to do their job. These operations are called stateful operations
stream also supports min and max operators that take a
query to find smallest transactions
Optional<Transaction> smallestTransaction =
transactions.stream()
.min(comparing(Transaction::getValue));
int calories = menu.stream()
.map(Dish::getCalories)
.reduce(0, Integer::sum);
int calories = menu.stream()
.map(Dish::getCalories)
.sum();
but map generates a Stream which may not necessarily be stream of primitives. so how can we sum them??
Primitive stream specializations to the rescue
Java 8 introduces three primitive specialized stream interfaces to tackle this issue, IntStream, DoubleStream, and LongStream
Each of these interfaces brings new methods to perform common numeric reductions such as sum to calculate the sum of a numeric stream and max to find the maximum element
int calories = menu.stream()
.mapToInt(Dish::getCalories)
.sum()
mapToInt returns an IntStream rather than Stream which prevents Unboxing
We can also convert this stream back to Stream
IntStream intStream = menu.stream().mapToInt(Dish::getCalories)
Stream<Integer> stream = instream.boxed()
to denote sum is Optional if stream is empty we have
a primitive specialized version of Optional as well for the three primitive stream specializations: OptionalInt, OptionalDouble, and OptionalLong.
OptionalInt maxCalories = menu.stream()
.mapToInt(Dish::getCalories)
.max();
IntStream evenNumbers = IntStream.rangeClosed(1,100).filter(n->n%2==0)
IntStream.rangeClosed(1, 100)
.filter(b -> Math.sqrt(a*a + b*b) % 1 == 0)
.boxed()
.map(b -> new int[]{a, b, (int) Math.sqrt(a * a + b * b)});
Since we have used IntStream we have to use boxed since map will return another Integer(as we have intStream) but we want a Stream<Integer[]>
We can also use mapToObj to achieve this
IntStream.rangeClosed(1, 100)
.filter(b -> Math.sqrt(a*a + b*b) % 1 == 0)
.mapToObj(b -> new int[]{a, b, (int) Math.sqrt(a * a + b * b)});
Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");
stream.map(String::toUpperCase).forEach(System.out::println);
Stream<String> emptyStream = Stream.empty();
int sum = Arrays.stream(numbers).sum()
Stream<String> lines =Files.lines(Paths.get("a.txt", Charset.defaultCharset())){
uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(""))
.distinct()
.count()
Stream.iterate(0, n -> n + 2)
.limit(10)
.forEach(System.out::println);
Stream.iterate(new int[]{0, 1},
t -> new int[]{t[1], t[0]+t[1]})
.limit(20)
.forEach(t -> System.out.println("(" + t[0] + "," + t[1] +")"))
Stream.generate(Math::random)
.limit(5)
.forEach(System.out::println);
Collectors are extremely useful because they provide a concise yet flexible way to define the criteria that collect uses to produce the resulting collection. More specifically, invoking the collect method on a stream triggers a reduction operation (parameterized by a Collector) on the elements of the stream itself
Typically, the Collector applies a transforming function to the element
List<Transaction> transactions =
transactionStream.collect(Collectors.toList());
Comparator<Dish> dishCaloriesComparator =
Comparator.comparingInt(Dish::getCalories);
Optional<Dish> mostCalorieDish =
menu.stream()
.collect(maxBy(dishCaloriesComparator));
int totalCalories = menu.stream().collect(summingInt(Dish::getCalories));
double avgCalories =
menu.stream().collect(averagingInt(Dish::getCalories));
IntSummaryStatistics menuStatistics =
menu.stream().collect(summarizingInt(Dish::getCalories));
int totalCalories = menu.stream().collect(reducing(
0, Dish::getCalories, (i, j) -> i + j));
reduce method is meant to combine two values and produce a new one; it’s an immutable reduction
the collect method is designed to mutate a container to accumulate the result it’s supposed to produce
the collect method is useful for expressing reduction working on a mutable container but crucially in a parallel-friendly way
Map<Dish.Type, List<Dish>> dishesByType =
menu.stream().collect(groupingBy(Dish::getType));
{FISH=[prawns, salmon], OTHER=[french fries, rice, season fruit, pizza],
MEAT=[pork, beef, chicken]}
public enum CaloricLevel { DIET, NORMAL, FAT }
Map<CaloricLevel, List<Dish>> dishesByCaloricLevel = menu.stream().collect(
groupingBy(dish -> {
if (dish.getCalories() <= 400) return CaloricLevel.DIET;
else if (dish.getCalories() <= 700) return
CaloricLevel.NORMAL;
else return CaloricLevel.FAT;
} ));
Runnable r1 = new Runnable(){
public void run(){
System.out.println("Hello");
}
};
Runnable r2 = () -> System.out.println("Hello");
Anonymous classes can shadow variables from the enclosing class but not lambda
int a =10
Runnable r1 = () -> {
int a =2 //compile error
}
eg
interface Task {
public void execute()
}
public static void doSomething(Runnable r){r.run()}
public static void doSomething(Task t){t.execute()};
doSomething(new Task(){
public void execute() {
System.out.println("Danger danger")
}
});
doSomething( () -> System.out.println("Danger danger"));