diff --git a/hw3/.idea/hw3.iml b/hw3/.idea/hw3.iml
new file mode 100644
index 0000000..b319ae2
--- /dev/null
+++ b/hw3/.idea/hw3.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hw3/.idea/misc.xml b/hw3/.idea/misc.xml
new file mode 100644
index 0000000..0c31c09
--- /dev/null
+++ b/hw3/.idea/misc.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hw3/.idea/modules.xml b/hw3/.idea/modules.xml
new file mode 100644
index 0000000..aa50f2a
--- /dev/null
+++ b/hw3/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hw3/.idea/vcs.xml b/hw3/.idea/vcs.xml
new file mode 100644
index 0000000..6c0b863
--- /dev/null
+++ b/hw3/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hw3/.idea/workspace.xml b/hw3/.idea/workspace.xml
new file mode 100644
index 0000000..986b4a9
--- /dev/null
+++ b/hw3/.idea/workspace.xml
@@ -0,0 +1,495 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ lang
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BIBTEX
+
+
+ $PROJECT_DIR$/submission.tex
+
+
+
+
+
+
+ PDFLATEX
+
+
+
+
+ $PROJECT_DIR$/submission.tex
+ false
+ false
+ PDF
+ BibTeX.submission bibliography
+
+
+
+
+
+ PDFLATEX
+ /Library/TeX/texbin/pdflatex
+
+ open -a Skim {pdf}
+
+ $PROJECT_DIR$/submission.tex
+ false
+ false
+ PDF
+ BibTeX.submission bibliography
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1575886303360
+
+
+ 1575886303360
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No facets are configured
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ hw3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hw3/ex3_test.txt b/hw3/ex3_test.txt
new file mode 100644
index 0000000..c7ce050
--- /dev/null
+++ b/hw3/ex3_test.txt
@@ -0,0 +1,4 @@
+abc
+xyz
+hello world
+play with streams
diff --git a/hw3/src/fp/FunctionsUtil.java b/hw3/src/fp/FunctionsUtil.java
new file mode 100644
index 0000000..7ee6284
--- /dev/null
+++ b/hw3/src/fp/FunctionsUtil.java
@@ -0,0 +1,15 @@
+package fp;
+
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+public class FunctionsUtil {
+ public static Function partial(BiFunction f, T x) {
+ return u -> f.apply(x, u);
+ }
+
+ public static void main(String... args) {
+ BiFunction f = String::startsWith;
+ System.out.println(FunctionsUtil.partial(f, "abc").apply("a")); // true
+ }
+}
diff --git a/hw3/src/fp/IntOperatorsUtil.java b/hw3/src/fp/IntOperatorsUtil.java
new file mode 100644
index 0000000..5f54ab7
--- /dev/null
+++ b/hw3/src/fp/IntOperatorsUtil.java
@@ -0,0 +1,31 @@
+package fp;
+
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntUnaryOperator;
+
+public class IntOperatorsUtil {
+ public static IntUnaryOperator compose(IntUnaryOperator... functions) {
+ IntUnaryOperator f = i -> i;
+ for (IntUnaryOperator g : functions) {
+ f = f.andThen(g);
+ }
+ return f;
+ }
+
+ public static IntUnaryOperator partial(IntBinaryOperator f, int x) {
+ return i -> f.applyAsInt(x, i);
+ }
+
+ public static void main(String... args) {
+ IntUnaryOperator[] functions = {
+ compose(),
+ compose(x -> x + 1),
+ compose(x -> x * 2, x -> x + 1),
+ compose(x -> x + 1, x -> x * 2),
+ compose(x -> x + 1, x -> x * 2, x -> x + 1)
+ };
+ for (IntUnaryOperator f : functions) System.out.println(f.applyAsInt(1));
+
+ IntOperatorsUtil.partial((x, y) -> x-y, 1).applyAsInt(2); // -1
+ }
+}
diff --git a/hw3/src/streams/FileLinesProcessor.java b/hw3/src/streams/FileLinesProcessor.java
new file mode 100644
index 0000000..98bd31e
--- /dev/null
+++ b/hw3/src/streams/FileLinesProcessor.java
@@ -0,0 +1,115 @@
+package streams;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+
+public class FileLinesProcessor {
+
+ private final String filename;
+
+ FileLinesProcessor(String filename) {
+ this.filename = filename;
+ }
+
+ private Stream getLines() throws IOException {
+ return Files.lines(Paths.get(filename));
+ }
+
+ public byte[][] fileLinesAsBytes() throws IOException {
+ return getLines().map(String::getBytes).toArray(byte[][]::new);
+ }
+
+ public long countByNumberOfSpaces(int n) throws IOException {
+ return getLines()
+ .map(s -> s.chars()
+ .filter(c -> c == ' ')
+ .count())
+ .filter(c -> c == n).count();
+ }
+
+ public String concatNth(int n) throws IOException {
+ return getLines()
+ .map(s -> n >= s.length() ? "" : s.substring(n, n + 1))
+ .collect(Collectors.joining());
+ }
+
+ public Map> groupByLineLength() throws IOException {
+ return getLines()
+ .collect(Collectors.groupingBy(String::length, Collectors.toList()));
+ }
+
+ public Map countCharsOccurrences() throws IOException {
+ return getLines()
+ .map(String::chars)
+ .reduce(IntStream.of(), IntStream::concat)
+ .boxed()
+ .collect(Collectors.groupingBy(i -> (char) (i & 0xFFFF), Collectors.counting()));
+ }
+
+ public Map countCharsOccurrences(int n) throws IOException {
+ return getLines()
+ .map(String::chars)
+ .reduce(IntStream.of(), IntStream::concat)
+ .boxed()
+ .collect(Collectors.groupingBy(i -> (char) (i & 0xFFFF), Collectors.counting()))
+ .entrySet()
+ .stream()
+ .filter(e -> e.getValue() > n)
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ }
+
+ public static void main(final String... args) throws IOException {
+ final FileLinesProcessor processor = new FileLinesProcessor("ex3_test.txt");
+ assert processor.fileLinesAsBytes()[0][1] == 'b';
+ assert processor.fileLinesAsBytes()[1][2] == 'z';
+ assert processor.countByNumberOfSpaces(0) == 2; // (i.e., "abc" and "xyz")
+ assert processor.countByNumberOfSpaces(2) == 1; // (i.e., "play with streams")
+ assert "axhp".equals(processor.concatNth(0));
+ assert "byel".equals(processor.concatNth(1));
+ assert "ly".equals(processor.concatNth(3));
+
+ final Map> expected = new HashMap<>();
+ expected.put(3, Arrays.asList("abc", "xyz"));
+ expected.put(11, Collections.singletonList("hello world"));
+ expected.put(17, Collections.singletonList("play with streams"));
+ assert expected.equals(processor.groupByLineLength()); // Expected result: {3=[abc, xyz], 11=[hello world],
+ // 17=[play with streams]}
+
+ final Map expected2 = new HashMap<>();
+ expected2.put(' ', 3L);
+ expected2.put('a', 3L);
+ expected2.put('b', 1L);
+ expected2.put('c', 1L);
+ expected2.put('d', 1L);
+ expected2.put('e', 2L);
+ expected2.put('h', 2L);
+ expected2.put('i', 1L);
+ expected2.put('l', 4L);
+ expected2.put('m', 1L);
+ expected2.put('o', 2L);
+ expected2.put('p', 1L);
+ expected2.put('r', 2L);
+ expected2.put('s', 2L);
+ expected2.put('t', 2L);
+ expected2.put('w', 2L);
+ expected2.put('x', 1L);
+ expected2.put('y', 2L);
+ expected2.put('z', 1L);
+ assert expected2.equals(processor.countCharsOccurrences()); // Expected result { =3, a=3, b=1, c=1, d=1, e=2,
+ // h=2, i=1, l=4, m=1, o=2, p=1, r=2, s=2, t=2, w=2,
+ // x=1, y=2, z=1}
+ final Map expected3 = new HashMap<>();
+ expected3.put(' ', 3L);
+ expected3.put('a', 3L);
+ expected3.put('l', 4L);
+ assert expected3.equals(processor.countCharsOccurrences(2)); // Expected result: { =3, a=3, l=4}
+
+ System.out.println("OK");
+ }
+}
diff --git a/hw3/submission.tex b/hw3/submission.tex
new file mode 100644
index 0000000..d2d555d
--- /dev/null
+++ b/hw3/submission.tex
@@ -0,0 +1,71 @@
+\documentclass[12pt,a4paper]{article}
+
+\usepackage[utf8]{inputenc}
+\usepackage[margin=2cm]{geometry}
+\usepackage{listings}
+\usepackage{xcolor}
+\usepackage{lmodern}
+
+\title{Howework 3 -- Programming Fundamentals 3}
+\author{Claudio Maggioni}
+
+\lstset{
+ basicstyle=\small\ttfamily,
+ frame=shadowbox,
+ rulesepcolor=\color{black},
+ columns=fullflexible,
+ commentstyle=\color{gray},
+ keywordstyle=\bfseries,
+ escapeinside={\%*}{*)},
+ aboveskip=2em,
+ captionpos=b,
+ abovecaptionskip=1em,
+ belowcaptionskip=1em
+}
+
+\begin{document}
+\maketitle
+\tableofcontents
+
+\section{Exercise 1}
+\subsection{Exercise 1.1}
+\paragraph{Example 1:}
+The code will compile and run normally since Integer implements Number
+and therefore it is a satisfiable parameter for
+\texttt{Box.put(Number)}.
+
+\paragraph{Example 2:}
+The code will compile, but it will terminate with a NullPointerException.
+The implicit unboxing of the return value of \texttt{iBox.get()} will call
+the method \texttt{intValue()} on the object returned. But, since the Box object
+contains an empty reference, this call will fail and thus cause a
+\texttt{NullPointerException}.
+
+\paragraph{Example 3:}
+This code will not compile since \texttt{Box.put()} requires an integer
+as an argument, but a \texttt{double} is provided.
+
+\subsection{Exercise 1.2}
+\begin{lstlisting}[language=Java, caption=New signature of Box.put(...)]
+public void put(Box extends T> box) { ... };
+\end{lstlisting}
+
+
+\subsection{Exercise 1.3}
+\begin{lstlisting}[language=Java, caption=New signature of Box.put(...)]
+public boolean containsSame(Box extends T> o,
+ EqualityComparator super T> c) { ... };
+\end{lstlisting}
+
+
+\section{Exercise 2}
+\subsection{Exercise 2.1}
+\begin{lstlisting}[language=Java, caption=BiPredicate with lambda]
+BiPredicate firstStartsWithSecond = (s, s2) -> s.startsWith(s2);
+\end{lstlisting}
+
+\begin{lstlisting}[language=Java, caption=BIPredicate with method reference]
+BiPredicate firstStartsWithSecond = String::startsWith;
+\end{lstlisting}
+
+\end{document}