diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..345e61a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,49 @@
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/dictionaries
+
+# Sensitive or high-churn files:
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.xml
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+
+# Gradle:
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# CMake
+cmake-build-debug/
+
+# Mongo Explorer plugin:
+.idea/**/mongoSettings.xml
+
+## File-based project format:
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..067d5ff
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..e8942bd
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..65c89bb
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Maybe.iml b/Maybe.iml
new file mode 100644
index 0000000..57f498f
--- /dev/null
+++ b/Maybe.iml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..fe36c91
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,36 @@
+
+
+ 4.0.0
+
+ ru.spbau.mit.kazakov.Maybe
+ Maybe
+ 1.0-SNAPSHOT
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+
+
+
+
+
+
+
+ junit
+ junit
+ 4.8
+
+
+ org.jetbrains
+ annotations
+ 13.0
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/ru/spbau/mit/kazakov/Maybe/GetNothingException.java b/src/main/java/ru/spbau/mit/kazakov/Maybe/GetNothingException.java
new file mode 100644
index 0000000..559714c
--- /dev/null
+++ b/src/main/java/ru/spbau/mit/kazakov/Maybe/GetNothingException.java
@@ -0,0 +1,7 @@
+package ru.spbau.mit.kazakov.Maybe;
+
+/**
+ * Exception thrown when there is no value to return.
+ */
+public class GetNothingException extends Exception {
+}
diff --git a/src/main/java/ru/spbau/mit/kazakov/Maybe/Main.java b/src/main/java/ru/spbau/mit/kazakov/Maybe/Main.java
new file mode 100644
index 0000000..020e039
--- /dev/null
+++ b/src/main/java/ru/spbau/mit/kazakov/Maybe/Main.java
@@ -0,0 +1,63 @@
+package ru.spbau.mit.kazakov.Maybe;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+/**
+ * Reads numbers from input file and writes squared values to output file. If read data isn't a number writes "null" instead.
+ */
+public class Main {
+ /**
+ * Primary method.
+ *
+ * @param args the first argument is input file and the second one is output file
+ */
+ public static void main(@NotNull String[] args) throws IOException, GetNothingException {
+ ArrayList> readData = new ArrayList<>();
+ try (Scanner scanner = new Scanner(new File(args[0]))) {
+ while (scanner.hasNextLine()) {
+ Integer value = tryParse(scanner.nextLine());
+ if (value == null) {
+ readData.add(Maybe.nothing());
+ } else {
+ readData.add(Maybe.just(value));
+ }
+ }
+ }
+
+ ArrayList> squaredNumber = new ArrayList<>();
+ for (Maybe maybeInt : readData) {
+ squaredNumber.add(maybeInt.map(value -> value * value));
+ }
+
+ try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(args[1]))) {
+ for (Maybe maybeInt : squaredNumber) {
+ if (maybeInt.isPresent()) {
+ bufferedWriter.write(maybeInt.get().toString());
+ } else {
+ bufferedWriter.write("null");
+ }
+ bufferedWriter.newLine();
+ }
+ }
+ }
+
+ /**
+ * Parses specified String to Integer.
+ *
+ * @return Integer if String was a number, and null otherwise
+ */
+ @Nullable
+ private static Integer tryParse(@NotNull String parsingString) {
+ try {
+ return Integer.parseInt(parsingString);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/ru/spbau/mit/kazakov/Maybe/Maybe.java b/src/main/java/ru/spbau/mit/kazakov/Maybe/Maybe.java
new file mode 100644
index 0000000..a7ca47c
--- /dev/null
+++ b/src/main/java/ru/spbau/mit/kazakov/Maybe/Maybe.java
@@ -0,0 +1,85 @@
+package ru.spbau.mit.kazakov.Maybe;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.function.Function;
+
+/**
+ * Generic container for storing a value or nothing.
+ */
+public class Maybe {
+ private static final Maybe NOTHING = new Maybe<>(null);
+
+ @Nullable
+ private final T value;
+
+ /**
+ * Assigns specified value to class's storing field.
+ *
+ * @param t specified value
+ */
+ private Maybe(@Nullable T t) {
+ value = t;
+ }
+
+ /**
+ * Creates an object for storing specified value.
+ *
+ * @param t specified value
+ * @return new object
+ */
+ @NotNull
+ public static Maybe just(T t) {
+ return new Maybe<>(t);
+ }
+
+ /**
+ * Creates an object for strong nothing.
+ *
+ * @return new object
+ */
+ @NotNull
+ public static Maybe nothing() {
+ return NOTHING;
+ }
+
+ /**
+ * Returns stored value or throws exception if there is no value.
+ *
+ * @return stored value
+ * @throws GetNothingException if there is no stored value
+ */
+ @NotNull
+ public T get() throws GetNothingException {
+ if (isPresent()) {
+ return value;
+ } else {
+ throw new GetNothingException();
+ }
+ }
+
+ /**
+ * Checks if there is stored value.
+ *
+ * @return true if there is stored value, and false otherwise
+ */
+ public boolean isPresent() {
+ return value != null;
+ }
+
+ /**
+ * Maps stored value of type T to another value of type U.
+ *
+ * @param mapper a function acting from T to V
+ * @param image's type
+ * @return Maybe object storing mapped value if there is a storing value, and Maybe object storing nothing otherwise
+ */
+ @NotNull
+ public Maybe map(@NotNull Function super T, ? extends U> mapper) {
+ if (!isPresent()) {
+ return nothing();
+ }
+ return just(mapper.apply(value));
+ }
+}
diff --git a/src/test/java/ru/spbau/mit/kazakov/Maybe/MainTest.java b/src/test/java/ru/spbau/mit/kazakov/Maybe/MainTest.java
new file mode 100644
index 0000000..35af725
--- /dev/null
+++ b/src/test/java/ru/spbau/mit/kazakov/Maybe/MainTest.java
@@ -0,0 +1,46 @@
+package ru.spbau.mit.kazakov.Maybe;
+
+import org.junit.Test;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
+
+import static org.junit.Assert.*;
+
+public class MainTest {
+ @Rule
+ public TemporaryFolder testFolder = new TemporaryFolder();
+
+ @Test
+ public void testMain() throws IOException, GetNothingException {
+ File input = testFolder.newFile("input.txt");
+ File output = testFolder.newFile("output.txt");
+
+ try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(input))) {
+ bufferedWriter.write("1\n0\n-3\nj\njava\n1b\n11 22\n");
+ }
+
+ Main.main(new String[]{input.getAbsolutePath(), output.getAbsolutePath()});
+
+
+ assertEquals("1\n0\n9\nnull\nnull\nnull\nnull\n", new String(Files.readAllBytes(Paths.get(output.getAbsolutePath()))));
+ }
+
+ @Test
+ public void testMainEmpty() throws IOException, GetNothingException {
+ File input = testFolder.newFile("input.txt");
+ File output = testFolder.newFile("output.txt");
+
+ Main.main(new String[]{input.getAbsolutePath(), output.getAbsolutePath()});
+
+ assertEquals("", new String(Files.readAllBytes(Paths.get(output.getAbsolutePath()))));
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/ru/spbau/mit/kazakov/Maybe/MaybeTest.java b/src/test/java/ru/spbau/mit/kazakov/Maybe/MaybeTest.java
new file mode 100644
index 0000000..a73aee0
--- /dev/null
+++ b/src/test/java/ru/spbau/mit/kazakov/Maybe/MaybeTest.java
@@ -0,0 +1,60 @@
+package ru.spbau.mit.kazakov.Maybe;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class MaybeTest {
+ @Test
+ public void testJustInteger() throws GetNothingException {
+ Maybe maybeInteger = Maybe.just(5);
+ int storedValue = maybeInteger.get();
+ assertEquals(5, storedValue);
+ }
+
+ @Test
+ public void testNothingBoolean() {
+ Maybe maybeBoolean = Maybe.nothing();
+ assertFalse(maybeBoolean.isPresent());
+ }
+
+ @Test
+ public void testGetDouble() throws GetNothingException {
+ Maybe maybeDouble = Maybe.just(-7.0);
+ double storedValue = maybeDouble.get();
+ assertEquals(-7.0, storedValue, 0.000000001);
+ }
+
+ @Test(expected = GetNothingException.class)
+ public void testGetCharacterThrowsException() throws GetNothingException {
+ Maybe maybeCharacter = Maybe.nothing();
+ char storedValue = maybeCharacter.get();
+ }
+
+ @Test
+ public void testIsPresentFalse() {
+ Maybe maybeBoolean = Maybe.nothing();
+ assertFalse(maybeBoolean.isPresent());
+ }
+
+ @Test
+ public void testIsPresentTrue() {
+ Maybe maybeString = Maybe.just("abacaba");
+ assertTrue(maybeString.isPresent());
+ }
+
+ @Test
+ public void testMapJust() throws GetNothingException {
+ Maybe maybeInteger = Maybe.just(10);
+ Maybe mappedMaybeInteger = maybeInteger.map(value -> value * value);
+ int mappedValue = mappedMaybeInteger.get();
+ assertEquals(100, mappedValue);
+ }
+
+ @Test
+ public void testMapNothing() throws GetNothingException {
+ Maybe maybeInteger = Maybe.nothing();
+ Maybe mappedMaybeInteger = maybeInteger.map(value -> value * value);
+ assertFalse(mappedMaybeInteger.isPresent());
+ }
+}
\ No newline at end of file