diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..596720d --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# Created by .ignore support plugin (hsz.mobi) +*.iml +*.idea +*.class +out/ +target/ +.DS_Store + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..650c469 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +language: java + +sudo: required + +jdk: oraclejdk8 + +install: true + +script: + mvn package +# sudo apt-get update +# sudo apt-get install oracle-java8-installer +# java -version \ No newline at end of file diff --git a/README.md b/README.md index a341794..5732606 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,18 @@ -# RandomJava -Please download spring-*.jar, apache-logging, JAF, Javamail and other necessary jars and put them onto your classpath or add them as external libraries, otherwise your IntelliJ/Eclipse won't smile. ^ ^ +# RandomJava [![Build Status](https://travis-ci.org/fishercoder1534/RandomJava.svg?branch=master)](https://travis-ci.org/fishercoder1534/RandomJava) +This is a Maven project containing a bunch of Random Java programs that I used, wrote from time to time. + +Build instructions: +* `git clone` this repo to your local, then open this application as a Maven project. +* If you get compile/run/IntelliJ errors, e.g. ClassNotFoundException when running in IntelliJ, just rm your package from your local machine, use IntelliJ to directly open: +File -> New -> Project from Version Control -> GitHub, then configure JDK8, then you'll fly with colors! ^ ^ +* run `mvn install` to install depedencies on your machine +* In your Intellij, click the Maven icon and click on Reload all Maven projects + +| Package/Theme | Code +|----------------|--------------- +|Avro|[Avro code](../master/src/main/java/avro) +|Java annotations|[annotations](../master/src/main/java/customize_annotations_generics_wildcards_examples) +|Design Patterns|[Design patterns](../master/src/main/java/designPatterns) +|Java Exceptions|[exceptions](../master/src/main/java/exceptionsCanBeSelfDefined) +|Some interview questions|[questions](../master/src/main/java/interviewQuestions) +|Java 8 tutorials|[Java 8](../master/src/main/java/java8tutorials) diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..ee65683 --- /dev/null +++ b/pom.xml @@ -0,0 +1,206 @@ + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 17 + 17 + + + + + + 4.0.0 + + com.fishercoder + RandomJava + 1.0-SNAPSHOT + + + + com.opencsv + opencsv + 5.9 + + + + org.apache.logging.log4j + log4j-api + 2.17.1 + + + org.apache.logging.log4j + log4j-core + 2.17.1 + + + + org.projectlombok + lombok + 1.18.20 + provided + + + + junit + junit + 4.13.1 + + + + org.junit.jupiter + junit-jupiter-engine + 5.9.2 + + + + org.junit.jupiter + junit-jupiter-params + 5.9.0 + + + + + org.springframework + spring-context + 4.1.6.RELEASE + + + + + org.springframework + spring-aop + 4.1.6.RELEASE + + + + + org.springframework + spring-webmvc + 5.3.18 + + + + + org.springframework + spring-web + 4.1.6.RELEASE + + + + org.codehaus.jackson + jackson-core-asl + 1.9.13 + compile + + + + org.codehaus.jackson + jackson-mapper-asl + 1.9.13 + compile + + + + javax.mail + mail + 1.5.0-b01 + + + + org.apache.avro + avro + 1.8.1 + + + + com.amazonaws + aws-java-sdk-ses + 1.11.253 + + + + + org.apache.spark + spark-core_2.12 + 3.1.1 + + + + org.apache.spark + spark-sql_2.12 + 3.0.1 + + + + com.google.inject + guice + 3.0 + + + + + com.google.collections + google-collections + 1.0 + + + + + com.google.inject + guice + LATEST + + + + org.slf4j + slf4j-simple + 1.7.30 + + + + com.backblaze.b2 + b2-sdk-core + 6.1.1 + compile + + + com.backblaze.b2 + b2-sdk-httpclient + 6.1.1 + compile + + + + org.skyscreamer + jsonassert + 1.5.1 + test + + + org.testng + testng + RELEASE + test + + + + org.springframework.security + spring-security-crypto + 6.3.1 + + + + + + diff --git a/src/main/java/IO_example/ExtractFieldsFromFile.java b/src/main/java/IO_example/ExtractFieldsFromFile.java new file mode 100644 index 0000000..1d96efc --- /dev/null +++ b/src/main/java/IO_example/ExtractFieldsFromFile.java @@ -0,0 +1,93 @@ +package IO_example; + +import java.io.*; +import java.util.HashSet; +import java.util.Scanner; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ExtractFieldsFromFile { + private static final String BASE_FILE = "/Users/Downloads/base_file"; + private static final String UPDATE_FILE = "/Users/Downloads/update_file"; + + public static void main(String... args) throws IOException { + System.out.println("Program started."); + readAllFieldNames(""); + Set baseSet = readAllFieldNames(BASE_FILE); + Set updateFileSet = readAllFieldNames(UPDATE_FILE); + Set baseSetCopy = new HashSet<>(baseSet); + baseSetCopy.removeAll(updateFileSet); + System.out.println("baseSetCopy size after removing updateFileSet is: " + baseSetCopy.size()); + + Set linesOnlyExistInBaseSet = readLinesMatchingSet(BASE_FILE, baseSetCopy); +// linesOnlyExistInBaseSet.forEach(System.out::println); + System.out.println("Found a total of " + linesOnlyExistInBaseSet.size() + " matches."); + + appendLinesToFile(UPDATE_FILE, linesOnlyExistInBaseSet); + + System.out.println("Program finished."); + } + + private static void appendLinesToFile(String updateFile, Set linesToBeAppended) throws IOException { + BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(updateFile, true)); + bufferedWriter.append("\n\n\n"); + bufferedWriter.append("#Added below fields from base file ---------\n"); + for (String str : linesToBeAppended) { + bufferedWriter.append(str); + bufferedWriter.append("\n"); + } + bufferedWriter.close(); + } + + private static Set readLinesMatchingSet(String filePath, Set set) throws FileNotFoundException { + if (filePath.isEmpty()) { + System.out.println("No file to read, exit."); + return null; + } + Scanner scanner = new Scanner(new File(filePath)); + scanner.useDelimiter("\n"); + Set lines = new HashSet<>(); + int i = 0; + while (scanner.hasNext()) { + String line = scanner.next(); + i++; + if (!line.isEmpty() && Character.isAlphabetic(line.charAt(0))) { + String[] parts = line.split("="); + if (set.contains(parts[0])) { + lines.add(line); + } + } + } + scanner.close(); + System.out.println("A total of " + i + " lines were gone through, and found a total of " + lines.size() + " matches."); + return lines; + } + + public static Set readAllFieldNames(String filePath) throws IOException { + if (filePath.isEmpty()) { + System.out.println("No file to read, exit."); + return null; + } + Scanner scanner = new Scanner(new File(filePath)); + scanner.useDelimiter("\n"); + + assertTrue(scanner.hasNext()); + int i = 0; + int nonEmptyLines = 0; + Set fields = new HashSet<>(); + while (scanner.hasNext()) { + String line = scanner.next(); + i++; + if (!line.isEmpty() && Character.isAlphabetic(line.charAt(0))) { + String[] parts = line.split("="); + fields.add(parts[0]); + nonEmptyLines++; + } + } + System.out.println("For this file: " + filePath + ": A total of " + i + " lines, in which " + nonEmptyLines + " are non empty."); + + scanner.close(); + return fields; + } +} diff --git a/src/sporadic/IO_example/JavaFileExample.java b/src/main/java/IO_example/JavaFileExample.java similarity index 98% rename from src/sporadic/IO_example/JavaFileExample.java rename to src/main/java/IO_example/JavaFileExample.java index 7dfc651..bc4d2bf 100644 --- a/src/sporadic/IO_example/JavaFileExample.java +++ b/src/main/java/IO_example/JavaFileExample.java @@ -1,4 +1,4 @@ -package sporadic.IO_example; +package IO_example; import java.io.File; diff --git a/src/main/java/IO_example/JavaFileIOExample.java b/src/main/java/IO_example/JavaFileIOExample.java new file mode 100644 index 0000000..e307e17 --- /dev/null +++ b/src/main/java/IO_example/JavaFileIOExample.java @@ -0,0 +1,49 @@ +package IO_example; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Scanner; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class JavaFileIOExample { + + public static void main(String... args) throws IOException { + System.out.println("Program started."); + readFileOnDisk("src/test/resources/sample_input.txt"); + findUniqueCityNames(); + System.out.println("Program finished."); + } + + public static void readFileOnDisk(String filePath) throws IOException { + Scanner scanner = new Scanner(new File(filePath)); + scanner.useDelimiter(" "); + + assertTrue(scanner.hasNext()); + while (scanner.hasNext()) { + System.out.println(scanner.next()); + } + + scanner.close(); + } + + private static void findUniqueCityNames() throws IOException { + String file = "src/test/resources/city_names.csv"; + Scanner scanner = new Scanner(new File(file)); + scanner.useDelimiter(","); + Map map = new HashMap<>(); + while (scanner.hasNext()) { + String city = scanner.next(); + map.put(city, map.getOrDefault(city, 0) + 1); + } + scanner.close(); + System.out.println("Unique city names are: "); + for (String city : map.keySet()) { + if (map.get(city) == 1) { + System.out.println(city); + } + } + } +} diff --git a/src/sporadic/IO_example/JavaIOExample.java b/src/main/java/IO_example/JavaIOExample.java similarity index 99% rename from src/sporadic/IO_example/JavaIOExample.java rename to src/main/java/IO_example/JavaIOExample.java index 260f108..3204c7d 100644 --- a/src/sporadic/IO_example/JavaIOExample.java +++ b/src/main/java/IO_example/JavaIOExample.java @@ -1,4 +1,4 @@ -package sporadic.IO_example; +package IO_example; import java.io.FileInputStream; import java.io.FileNotFoundException; diff --git a/src/main/java/abstractClass/StreamExample.java b/src/main/java/abstractClass/StreamExample.java new file mode 100644 index 0000000..bd5d582 --- /dev/null +++ b/src/main/java/abstractClass/StreamExample.java @@ -0,0 +1,18 @@ +package abstractClass; + +import java.util.ArrayList; +import java.util.List; + +/** + * created by stevesun on 11/26/18/. + */ +public class StreamExample { + public static void main(String... args) { + + /**This simple example shows that it's safe to run stream operation on an empty list.*/ + List list = new ArrayList<>(); + list.stream() + .map(i -> i + 1); + System.out.println("Finished."); + } +} diff --git a/src/main/java/amazonses/AmazonSESSample.java b/src/main/java/amazonses/AmazonSESSample.java new file mode 100644 index 0000000..9337e86 --- /dev/null +++ b/src/main/java/amazonses/AmazonSESSample.java @@ -0,0 +1,72 @@ +package amazonses; + +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.regions.Regions; +import com.amazonaws.services.simpleemail.AmazonSimpleEmailService; +import com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClient; +import com.amazonaws.services.simpleemail.model.Body; +import com.amazonaws.services.simpleemail.model.Content; +import com.amazonaws.services.simpleemail.model.Destination; +import com.amazonaws.services.simpleemail.model.Message; +import com.amazonaws.services.simpleemail.model.SendEmailRequest; +import java.io.IOException; + +public class AmazonSESSample { + // Replace sender@example.com with your "From" address. + // This address must be verified with Amazon SES. + static final String FROM = "fishercoder@gmail.com"; + + // Replace recipient@example.com with a "To" address. If your account + // is still in the sandbox, this address must be verified. + static final String TO = "stevejsun@gmail.com"; + + // The configuration set to use for this email. If you do not want to use a + // configuration set, comment the following variable and the + // .withConfigurationSetName(CONFIGSET); argument below. + //static final String CONFIGSET = "ConfigSet"; + + // The subject line for the email. + static final String SUBJECT = "Amazon SES test (AWS SDK for Java)"; + + // The HTML body for the email. + static final String HTMLBODY = "

Amazon SES test (AWS SDK for Java)

" + + "

This email was sent with " + + "Amazon SES using the " + + "AWS SDK for Java"; + + // The email body for recipients with non-HTML email clients. + static final String TEXTBODY = "This email was sent through Amazon SES " + + "using the AWS SDK for Java."; + + public static void main(String[] args) throws IOException { + + try { + + BasicAWSCredentials credentials = new BasicAWSCredentials("ACCESS_KEY", "SECRET_KEY"); + AmazonSimpleEmailService client = + new AmazonSimpleEmailServiceClient(credentials).withRegion(Regions.US_WEST_2); + //AmazonSimpleEmailServiceClientBuilder.standard().withRegion(Regions.US_WEST_2).build(); + SendEmailRequest request = new SendEmailRequest() + .withDestination( + new Destination().withToAddresses(TO)) + .withMessage(new Message() + .withBody(new Body() + .withHtml(new Content() + .withCharset("UTF-8").withData(HTMLBODY)) + .withText(new Content() + .withCharset("UTF-8").withData(TEXTBODY))) + .withSubject(new Content() + .withCharset("UTF-8").withData(SUBJECT))) + .withSource(FROM) + // Comment or remove the next line if you are not using a + // configuration set + //.withConfigurationSetName(CONFIGSET) + ; + client.sendEmail(request); + System.out.println("Email sent!"); + } catch (Exception ex) { + System.out.println("The email was not sent. Error message: " + + ex.getMessage()); + } + } +} diff --git a/src/main/java/avro/apacheExample/ApacheExample.java b/src/main/java/avro/apacheExample/ApacheExample.java new file mode 100644 index 0000000..98b56dd --- /dev/null +++ b/src/main/java/avro/apacheExample/ApacheExample.java @@ -0,0 +1,53 @@ +package avro.apacheExample; + +import org.apache.avro.Schema; +import org.apache.avro.file.DataFileReader; +import org.apache.avro.file.DataFileWriter; +import org.apache.avro.generic.GenericData; +import org.apache.avro.generic.GenericDatumReader; +import org.apache.avro.generic.GenericDatumWriter; +import org.apache.avro.generic.GenericRecord; +import org.apache.avro.io.DatumReader; +import org.apache.avro.io.DatumWriter; + +import java.io.File; +import java.io.IOException; + +/** + * This code is credited to: http://hadooptutorial.info/avro-serializing-and-deserializing-example-java-api/ + * Created by stevesun on 1/24/17. + */ +public class ApacheExample { + public static void main(String[] args) throws IOException { + Schema schema = new Schema.Parser().parse(new File("/Users/stevesun/personal_dev/RandomJava/src/main/java/avro/apacheExample/Employee.avsc")); + GenericRecord emp1 = new GenericData.Record(schema); + emp1.put("name", "Siva"); + emp1.put("age", 45); + + GenericRecord emp2 = new GenericData.Record(schema); + emp2.put("name", "Krish"); + emp2.put("age", 28); + + File file = new File("/Users/stevesun/personal_dev/RandomJava/src/main/java/avro/apacheExample/output.avro"); + DatumWriter datumWriter = new GenericDatumWriter(schema); + DataFileWriter dataFileWriter = new DataFileWriter(datumWriter); + dataFileWriter.create(schema, file); + dataFileWriter.append(emp1); + dataFileWriter.append(emp2); + dataFileWriter.close(); + System.out.println("Serialization finished."); + + File fileToDeserialize = new File("/Users/stevesun/personal_dev/RandomJava/src/main/java/avro/apacheExample/output.avro"); + + DatumReader datumReader = new GenericDatumReader(schema); + DataFileReader dataFileReader = new DataFileReader(file, datumReader); + + GenericRecord emp = new GenericData.Record(schema); + while (dataFileReader.hasNext()) { + emp = dataFileReader.next(); + System.out.println(emp); + } + + System.out.println("Program finished."); + } +} diff --git a/src/main/java/avro/apacheExample/Employee.avsc b/src/main/java/avro/apacheExample/Employee.avsc new file mode 100644 index 0000000..5790674 --- /dev/null +++ b/src/main/java/avro/apacheExample/Employee.avsc @@ -0,0 +1,9 @@ +{ + "type": "record", + "name": "Employee", + "fields": [ + {"name": "name", "type": "string"}, + {"name": "age", "type": "int"}, + {"name": "boss", "type": ["Employee","null"]} + ] +} \ No newline at end of file diff --git a/src/main/java/avro/apacheExample/output.avro b/src/main/java/avro/apacheExample/output.avro new file mode 100644 index 0000000..5a5e900 Binary files /dev/null and b/src/main/java/avro/apacheExample/output.avro differ diff --git a/src/main/java/avro/rfoldesExample/Employee.avsc b/src/main/java/avro/rfoldesExample/Employee.avsc new file mode 100644 index 0000000..c2e609f --- /dev/null +++ b/src/main/java/avro/rfoldesExample/Employee.avsc @@ -0,0 +1,10 @@ +{ + "type": "record", + "name": "Employee", + "fields": [ + {"name": "name", "type": "string"}, + {"name": "age", "type": "int"}, + {"name": "emails", "type": {"type": "array", "items": "string"}}, + {"name": "boss", "type": ["Employee","null"]} + ] +} \ No newline at end of file diff --git a/src/main/java/avro/rfoldesExample/Employee.java b/src/main/java/avro/rfoldesExample/Employee.java new file mode 100644 index 0000000..2287ffe --- /dev/null +++ b/src/main/java/avro/rfoldesExample/Employee.java @@ -0,0 +1,172 @@ +package avro.rfoldesExample; + +import org.apache.avro.Schema; +import org.apache.avro.file.DataFileReader; +import org.apache.avro.file.DataFileWriter; +import org.apache.avro.generic.GenericData; +import org.apache.avro.generic.GenericDatumReader; +import org.apache.avro.generic.GenericDatumWriter; +import org.apache.avro.io.Encoder; +import org.apache.avro.io.EncoderFactory; +import org.apache.avro.util.Utf8; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Broken!! + * + * I copied this example from https://github.com/rfoldes/Avro-Test, but it throws NPE, so I filed an issue here: https://github.com/rfoldes/Avro-Test/issues/1 + */ +public class Employee { + public static Schema SCHEMA; //writer's schema + public static Schema SCHEMA2; //reader's schema + + static { + try { + InputStream is = Employee.class.getResourceAsStream("Employee.avsc"); + SCHEMA = Schema.parse(is); + SCHEMA2 = Schema.parse(Employee.class.getResourceAsStream("Employee2.avsc")); + } + catch (IOException e) + { + System.out.println("Couldn't load a schema: "+e.getMessage()); + } + } + + private String name; + private int age; + private String[] mails; + private Employee boss; + + public Employee(String name, int age, String[] emails, Employee b){ + this.name = name; + this.age = age; + this.mails = emails; + this.boss = b; + } + + /** + * This method serializes the java object into Avro record. + * @return Avro generic record + */ + public GenericData.Record serialize() { + GenericData.Record record = new GenericData.Record(SCHEMA); + + record.put("name", this.name); + record.put("age", this.age); + + + int nemails = (mails != null) ? this.mails.length : 0; + GenericData.Array emails = new GenericData.Array(nemails, SCHEMA.getField("emails").schema()); + for (int i = 0; i < nemails; ++i) + emails.add(new Utf8(this.mails[i])); + record.put("emails", emails); + + if (this.boss != null) + record.put("boss", this.boss.serialize()); + + return record; + } + + /** + * Writes out Java objects into a binary Avro-encoded file + * @param file where to store serialized Avro records + * @param people is an array of objects to be serialized + * @throws IOException + */ + public static void testWrite(File file, Employee[] people) throws IOException { + GenericDatumWriter datum = new GenericDatumWriter(Employee.SCHEMA); + DataFileWriter writer = new DataFileWriter(datum); + + writer.setMeta("Meta-Key0", "Meta-Value0"); + writer.setMeta("Meta-Key1", "Meta-Value1"); + + writer.create(Employee.SCHEMA, file); + for (Employee p : people) + writer.append(p.serialize()); + + writer.close(); + } + + /** + * Writes out Java objects into a JSON-encoded file + * @param file where to store serialized Avro records + * @param people people is an array of objects to be serialized + * @throws IOException + */ + public static void testJsonWrite(File file, Employee[] people) throws IOException { + GenericDatumWriter writer = new GenericDatumWriter(Employee.SCHEMA); + Encoder e = EncoderFactory.get().jsonEncoder(Employee.SCHEMA, new FileOutputStream(file)); + + for (Employee p : people) + writer.write(p.serialize(), e); + + e.flush(); + } + + /** + * Reads in binary Avro-encoded entities using the schema stored in the file and prints them out. + * @param file + * @throws IOException + */ + public static void testRead(File file) throws IOException { + GenericDatumReader datum = new GenericDatumReader(); + DataFileReader reader = new DataFileReader(file, datum); + + GenericData.Record record = new GenericData.Record(reader.getSchema()); + while (reader.hasNext()) { + reader.next(record); + System.out.println("Name " + record.get("name") + + " Age " + record.get("age") + + " @ "+record.get("emails")); + } + + reader.close(); + } + + /** + * Reads in binary Avro-encoded entities using a schema that is different from the writer's schema. + * @param file + * @throws IOException + */ + public static void testRead2(File file) throws IOException { + GenericDatumReader datum = new GenericDatumReader(Employee.SCHEMA2); + DataFileReader reader = new DataFileReader(file, datum); + + GenericData.Record record = new GenericData.Record(Employee.SCHEMA2); + while (reader.hasNext()) { + reader.next(record); + System.out.println("Name " + record.get("name") + + " " + record.get("yrs") + " yrs old " + + " Gender " + record.get("gender") + + " @ "+record.get("emails")); + } + + reader.close(); + } + + public static void main(String[] args) { + Employee e1 = new Employee("Joe",31,new String[] {"joe@abc.com","joe@gmail.com"},null); + Employee e2 = new Employee("Jane",30,null,e1); + Employee e3 = new Employee("Zoe",21,null,e2); + Employee[] all = new Employee[] {e1,e2,e3}; + + File bf = new File("test.avro"); + File jf = new File("test.json"); + + try { + testWrite(bf,all); + testRead(bf); + testRead2(bf); + + testJsonWrite(jf,all); + } + catch (IOException e) { + System.out.println("Main: "+e.getMessage()); + } + } + +} diff --git a/src/main/java/avro/rfoldesExample/Employee2.avsc b/src/main/java/avro/rfoldesExample/Employee2.avsc new file mode 100644 index 0000000..0483706 --- /dev/null +++ b/src/main/java/avro/rfoldesExample/Employee2.avsc @@ -0,0 +1,10 @@ +{ + "type": "record", + "name": "Employee", + "fields": [ + {"name": "name", "type": "string"}, + {"name": "yrs", "type": "int", "aliases": ["age"]}, + {"name": "gender", "type": "string", "default":"unknown"}, + {"name": "emails", "type": {"type": "array", "items": "string"}} + ] +} \ No newline at end of file diff --git a/src/main/java/b2SdkExamples/B2SdkExamples.java b/src/main/java/b2SdkExamples/B2SdkExamples.java new file mode 100644 index 0000000..0c3166d --- /dev/null +++ b/src/main/java/b2SdkExamples/B2SdkExamples.java @@ -0,0 +1,70 @@ +package b2SdkExamples; + +import com.backblaze.b2.client.B2StorageClient; +import com.backblaze.b2.client.B2StorageClientFactory; +import com.backblaze.b2.client.contentSources.B2ByteArrayContentSource; +import com.backblaze.b2.client.contentSources.B2ContentTypes; +import com.backblaze.b2.client.exceptions.B2Exception; +import com.backblaze.b2.client.structures.*; + +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class B2SdkExamples { + private static final String APPLICATION_KEY_ID = "xxx"; + private static final String APPLICATION_KEY = "yyy"; + + + private static final String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36"; + + private static final int minimumPartSize = 5000000; +// TODO: read in a big file or generate a random file to fill into below byte array + private static final byte[] large_file_in_bytes = new byte[minimumPartSize + 1]; + + public static void main(String... args) throws B2Exception { + System.out.println("Hello world from B2SdkExamples.."); +// B2StorageClient client = B2StorageClientFactory.createDefaultFactory().create(USER_AGENT); + //set up B2 CLI + //and then use b2 get-account-info to get applicationKeyId and applicationKey to fill in here and run + B2ListBucketsResponse b2ListBucketsResponse; + try (B2StorageClient b2Client = B2StorageClientFactory.createDefaultFactory().create(APPLICATION_KEY_ID, APPLICATION_KEY, USER_AGENT)) { + b2ListBucketsResponse = b2Client.listBuckets(); + List buckets = b2ListBucketsResponse.getBuckets(); + System.out.println("buckets.size() is: " + buckets.size()); + B2Bucket bucketOne = null; + for (B2Bucket b2Bucket : buckets) { + System.out.println("this bucket info is: " + b2Bucket.getBucketInfo()); + System.out.println("this bucket getBucketName is: " + b2Bucket.getBucketName()); + bucketOne = b2Bucket; + break; + } + String b2AccountId = b2Client.getAccountId(); + System.out.println("b2AccountId is: " + b2AccountId); + + B2FileVersion largeFile = b2Client.startLargeFile( + B2StartLargeFileRequest + .builder(bucketOne.getBucketId(), "this_is_a_large_test_file_jsun", "text/plain") + .build() + ); + B2UploadPartUrlResponse uploadPartUrl = b2Client.getUploadPartUrl(B2GetUploadPartUrlRequest.builder(largeFile.getFileId()).build()); + System.out.println("uploadPartUrl.getFileId() is: " + uploadPartUrl.getFileId()); + System.out.println("uploadPartUrl.getUploadUrl() is: " + uploadPartUrl.getUploadUrl()); +// example output: +// uploadPartUrl.getFileId() is: 4_zc0c2ee6e6dccd2d788960d17_f231f3059ce9d1672_d20231118_m042524_c004_v0402007_t0004_u01700281524855 +// uploadPartUrl.getUploadUrl() is: https://pod-040-2007-12.backblaze.com/b2api/v2/b2_upload_part/4_zc0c2ee6e6dccd2d788960d17_f231f3059ce9d1672_d20231118_m042524_c004_v0402007_t0004_u01700281524855/0014 + +// TODO: figure out how to make below API call work elegantly + final B2UploadFileRequest request = B2UploadFileRequest.builder( + bucketOne.getBucketId(), + "largeFile", + B2ContentTypes.TEXT_PLAIN, + B2ByteArrayContentSource.build(large_file_in_bytes) + ).build(); + ExecutorService executor = Executors.newScheduledThreadPool(15); + B2FileVersion uploaded = b2Client.uploadLargeFile(request, executor); + System.out.println("uploaded.getLargeFileSha1OrNull(): " + uploaded.getLargeFileSha1OrNull()); + } + System.out.println("Finished running in main method."); + } +} diff --git a/src/main/java/bitoperators/MainApp.java b/src/main/java/bitoperators/MainApp.java new file mode 100644 index 0000000..4001fe1 --- /dev/null +++ b/src/main/java/bitoperators/MainApp.java @@ -0,0 +1,15 @@ +package bitoperators; + +public class MainApp { + + public static void main(String... args) { + int value1 = 3; + int value2 = 4; + System.out.println(Integer.toBinaryString(value1)); + System.out.println(Integer.toBinaryString(value2)); + + int result = value1 ^ value2; + System.out.println(result); + System.out.println(Integer.toBinaryString(result)); + } +} diff --git a/src/sporadic/customize_annotations_generics_wildcards_examples/AnotherSimpleTestCase.java b/src/main/java/customize_annotations_generics_wildcards_examples/AnotherSimpleTestCase.java similarity index 83% rename from src/sporadic/customize_annotations_generics_wildcards_examples/AnotherSimpleTestCase.java rename to src/main/java/customize_annotations_generics_wildcards_examples/AnotherSimpleTestCase.java index 3a7d85c..7c27453 100644 --- a/src/sporadic/customize_annotations_generics_wildcards_examples/AnotherSimpleTestCase.java +++ b/src/main/java/customize_annotations_generics_wildcards_examples/AnotherSimpleTestCase.java @@ -1,4 +1,4 @@ -package sporadic.customize_annotations_generics_wildcards_examples; +package customize_annotations_generics_wildcards_examples; public class AnotherSimpleTestCase { diff --git a/src/sporadic/customize_annotations_generics_wildcards_examples/Main.java b/src/main/java/customize_annotations_generics_wildcards_examples/Main.java similarity index 88% rename from src/sporadic/customize_annotations_generics_wildcards_examples/Main.java rename to src/main/java/customize_annotations_generics_wildcards_examples/Main.java index 9889bfa..3e7beea 100644 --- a/src/sporadic/customize_annotations_generics_wildcards_examples/Main.java +++ b/src/main/java/customize_annotations_generics_wildcards_examples/Main.java @@ -1,4 +1,4 @@ -package sporadic.customize_annotations_generics_wildcards_examples; +package customize_annotations_generics_wildcards_examples; import java.io.IOException; import java.util.ArrayList; diff --git a/src/sporadic/customize_annotations_generics_wildcards_examples/MyTestRunner.java b/src/main/java/customize_annotations_generics_wildcards_examples/MyTestRunner.java similarity index 96% rename from src/sporadic/customize_annotations_generics_wildcards_examples/MyTestRunner.java rename to src/main/java/customize_annotations_generics_wildcards_examples/MyTestRunner.java index c57df00..20fafd0 100644 --- a/src/sporadic/customize_annotations_generics_wildcards_examples/MyTestRunner.java +++ b/src/main/java/customize_annotations_generics_wildcards_examples/MyTestRunner.java @@ -1,4 +1,4 @@ -package sporadic.customize_annotations_generics_wildcards_examples; +package customize_annotations_generics_wildcards_examples; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; diff --git a/src/main/java/customize_annotations_generics_wildcards_examples/MyTestState.java b/src/main/java/customize_annotations_generics_wildcards_examples/MyTestState.java new file mode 100644 index 0000000..cb2f721 --- /dev/null +++ b/src/main/java/customize_annotations_generics_wildcards_examples/MyTestState.java @@ -0,0 +1,5 @@ +package customize_annotations_generics_wildcards_examples; + +public enum MyTestState { + ACTIVE, INACTIVE +} diff --git a/src/sporadic/customize_annotations_generics_wildcards_examples/SimpleTestCase.java b/src/main/java/customize_annotations_generics_wildcards_examples/SimpleTestCase.java similarity index 89% rename from src/sporadic/customize_annotations_generics_wildcards_examples/SimpleTestCase.java rename to src/main/java/customize_annotations_generics_wildcards_examples/SimpleTestCase.java index b2b9c95..7463570 100644 --- a/src/sporadic/customize_annotations_generics_wildcards_examples/SimpleTestCase.java +++ b/src/main/java/customize_annotations_generics_wildcards_examples/SimpleTestCase.java @@ -1,4 +1,4 @@ -package sporadic.customize_annotations_generics_wildcards_examples; +package customize_annotations_generics_wildcards_examples; import org.junit.Assert; diff --git a/src/sporadic/customize_annotations_generics_wildcards_examples/SteveSunFirstCustomAnnotation.java b/src/main/java/customize_annotations_generics_wildcards_examples/SteveSunFirstCustomAnnotation.java similarity index 88% rename from src/sporadic/customize_annotations_generics_wildcards_examples/SteveSunFirstCustomAnnotation.java rename to src/main/java/customize_annotations_generics_wildcards_examples/SteveSunFirstCustomAnnotation.java index da949a5..9847ada 100644 --- a/src/sporadic/customize_annotations_generics_wildcards_examples/SteveSunFirstCustomAnnotation.java +++ b/src/main/java/customize_annotations_generics_wildcards_examples/SteveSunFirstCustomAnnotation.java @@ -1,4 +1,4 @@ -package sporadic.customize_annotations_generics_wildcards_examples; +package customize_annotations_generics_wildcards_examples; import java.lang.annotation.Retention; import java.lang.annotation.Target; diff --git a/src/main/java/dateTimezone/DateVsLocalDateTime.java b/src/main/java/dateTimezone/DateVsLocalDateTime.java new file mode 100644 index 0000000..6490e2c --- /dev/null +++ b/src/main/java/dateTimezone/DateVsLocalDateTime.java @@ -0,0 +1,23 @@ +package dateTimezone; + +import java.time.LocalDateTime; +import java.util.Date; + +public class DateVsLocalDateTime { + public static void main(String... args) throws InterruptedException { + Date startDate = new Date(); + LocalDateTime startLocalDateTime = LocalDateTime.now(); + System.out.println("date is: " + startDate); + System.out.println("localDateTime is: " + startLocalDateTime); + Thread.sleep(1000); + Date endDate = new Date(); + LocalDateTime endLocalDateTime = LocalDateTime.now(); + System.out.println("date is: " + endDate); + System.out.println("localDateTime is: " + endLocalDateTime); + + long duration1 = ((endDate.getTime() - startDate.getTime()) / 1000); + long duration2 = (endLocalDateTime.getSecond() - startLocalDateTime.getSecond()); + System.out.println("duration1 is: " + duration1); + System.out.println("duration2 is: " + duration2); + } +} diff --git a/src/main/java/dateTimezone/Main.java b/src/main/java/dateTimezone/Main.java new file mode 100644 index 0000000..ad7ecdd --- /dev/null +++ b/src/main/java/dateTimezone/Main.java @@ -0,0 +1,18 @@ +package dateTimezone; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; + +public class Main { + + public static void main(String... args) { + LocalDateTime currentTime = LocalDateTime.now(); + System.out.println("currentTime is: " + currentTime); + LocalDateTime utcTime = LocalDateTime.now(ZoneOffset.UTC); + System.out.println("utcTime is: " + utcTime); + //use below method to convert a LocalDateTime object to its UTC version + LocalDateTime utcTimeConverted = currentTime.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime(); // UTC + System.out.println("utcTimeConverted is: " + utcTimeConverted); + } +} diff --git a/src/main/java/designPatterns/adapter_and_facade_pattern/TestDrive.java b/src/main/java/designPatterns/adapter_and_facade_pattern/TestDrive.java new file mode 100644 index 0000000..b9bc057 --- /dev/null +++ b/src/main/java/designPatterns/adapter_and_facade_pattern/TestDrive.java @@ -0,0 +1,11 @@ +package designPatterns.adapter_and_facade_pattern; + +public class TestDrive { + + public static void main(String... args){ + System.out.println("Program started."); + + System.out.println("Program ended."); + } + +} diff --git a/src/main/java/designPatterns/command_pattern/TestDrive.java b/src/main/java/designPatterns/command_pattern/TestDrive.java new file mode 100644 index 0000000..c0917f4 --- /dev/null +++ b/src/main/java/designPatterns/command_pattern/TestDrive.java @@ -0,0 +1,11 @@ +package designPatterns.command_pattern; + +public class TestDrive { + + public static void main(String... args){ + System.out.println("Program started."); + + System.out.println("Program ended."); + } + +} diff --git a/src/main/java/designPatterns/compound_pattern/TestDrive.java b/src/main/java/designPatterns/compound_pattern/TestDrive.java new file mode 100644 index 0000000..3b12daf --- /dev/null +++ b/src/main/java/designPatterns/compound_pattern/TestDrive.java @@ -0,0 +1,11 @@ +package designPatterns.compound_pattern; + +public class TestDrive { + + public static void main(String... args){ + System.out.println("Program started."); + + System.out.println("Program ended."); + } + +} diff --git a/src/designPatterns/chapter_3_decorator_pattern/Beverage.java b/src/main/java/designPatterns/decorator_pattern/Beverage.java similarity index 52% rename from src/designPatterns/chapter_3_decorator_pattern/Beverage.java rename to src/main/java/designPatterns/decorator_pattern/Beverage.java index 8585a7f..e6ffd11 100644 --- a/src/designPatterns/chapter_3_decorator_pattern/Beverage.java +++ b/src/main/java/designPatterns/decorator_pattern/Beverage.java @@ -1,10 +1,11 @@ -package designPatterns.chapter_3_decorator_pattern; - -import lombok.Getter; +package designPatterns.decorator_pattern; public abstract class Beverage { - @Getter String description = "Unknown beverage"; - + + public String getDescription() { + return description; + } + public abstract double cost(); } diff --git a/src/designPatterns/chapter_3_decorator_pattern/CondimentDecorator.java b/src/main/java/designPatterns/decorator_pattern/CondimentDecorator.java similarity index 66% rename from src/designPatterns/chapter_3_decorator_pattern/CondimentDecorator.java rename to src/main/java/designPatterns/decorator_pattern/CondimentDecorator.java index 3fea6aa..d689ebe 100644 --- a/src/designPatterns/chapter_3_decorator_pattern/CondimentDecorator.java +++ b/src/main/java/designPatterns/decorator_pattern/CondimentDecorator.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_3_decorator_pattern; +package designPatterns.decorator_pattern; public abstract class CondimentDecorator extends Beverage { public abstract String getDescription(); diff --git a/src/designPatterns/chapter_3_decorator_pattern/DecoratorPatternTestDrive.java b/src/main/java/designPatterns/decorator_pattern/DecoratorPatternTestDrive.java similarity index 93% rename from src/designPatterns/chapter_3_decorator_pattern/DecoratorPatternTestDrive.java rename to src/main/java/designPatterns/decorator_pattern/DecoratorPatternTestDrive.java index 936faea..b7f5055 100644 --- a/src/designPatterns/chapter_3_decorator_pattern/DecoratorPatternTestDrive.java +++ b/src/main/java/designPatterns/decorator_pattern/DecoratorPatternTestDrive.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_3_decorator_pattern; +package designPatterns.decorator_pattern; /**Classes should be open for extension and closed for modification. * diff --git a/src/designPatterns/chapter_3_decorator_pattern/Espresso.java b/src/main/java/designPatterns/decorator_pattern/Espresso.java similarity index 74% rename from src/designPatterns/chapter_3_decorator_pattern/Espresso.java rename to src/main/java/designPatterns/decorator_pattern/Espresso.java index 2b302e0..7890d11 100644 --- a/src/designPatterns/chapter_3_decorator_pattern/Espresso.java +++ b/src/main/java/designPatterns/decorator_pattern/Espresso.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_3_decorator_pattern; +package designPatterns.decorator_pattern; public class Espresso extends Beverage { diff --git a/src/designPatterns/chapter_3_decorator_pattern/HouseBlend.java b/src/main/java/designPatterns/decorator_pattern/HouseBlend.java similarity index 76% rename from src/designPatterns/chapter_3_decorator_pattern/HouseBlend.java rename to src/main/java/designPatterns/decorator_pattern/HouseBlend.java index 5ae7f59..e3bdd6f 100644 --- a/src/designPatterns/chapter_3_decorator_pattern/HouseBlend.java +++ b/src/main/java/designPatterns/decorator_pattern/HouseBlend.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_3_decorator_pattern; +package designPatterns.decorator_pattern; public class HouseBlend extends Beverage { diff --git a/src/designPatterns/chapter_3_decorator_pattern/Mocha.java b/src/main/java/designPatterns/decorator_pattern/Mocha.java similarity index 85% rename from src/designPatterns/chapter_3_decorator_pattern/Mocha.java rename to src/main/java/designPatterns/decorator_pattern/Mocha.java index f9a2e88..0cb906e 100644 --- a/src/designPatterns/chapter_3_decorator_pattern/Mocha.java +++ b/src/main/java/designPatterns/decorator_pattern/Mocha.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_3_decorator_pattern; +package designPatterns.decorator_pattern; public class Mocha extends CondimentDecorator { diff --git a/src/designPatterns/chapter_3_decorator_pattern/Soy.java b/src/main/java/designPatterns/decorator_pattern/Soy.java similarity index 85% rename from src/designPatterns/chapter_3_decorator_pattern/Soy.java rename to src/main/java/designPatterns/decorator_pattern/Soy.java index 581e71b..bcaec73 100644 --- a/src/designPatterns/chapter_3_decorator_pattern/Soy.java +++ b/src/main/java/designPatterns/decorator_pattern/Soy.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_3_decorator_pattern; +package designPatterns.decorator_pattern; public class Soy extends CondimentDecorator { diff --git a/src/designPatterns/chapter_3_decorator_pattern/Whip.java b/src/main/java/designPatterns/decorator_pattern/Whip.java similarity index 85% rename from src/designPatterns/chapter_3_decorator_pattern/Whip.java rename to src/main/java/designPatterns/decorator_pattern/Whip.java index 3882694..d74da32 100644 --- a/src/designPatterns/chapter_3_decorator_pattern/Whip.java +++ b/src/main/java/designPatterns/decorator_pattern/Whip.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_3_decorator_pattern; +package designPatterns.decorator_pattern; public class Whip extends CondimentDecorator { diff --git a/src/designPatterns/factory_pattern/Circle.java b/src/main/java/designPatterns/factory_pattern/Circle.java similarity index 100% rename from src/designPatterns/factory_pattern/Circle.java rename to src/main/java/designPatterns/factory_pattern/Circle.java diff --git a/src/designPatterns/factory_pattern/MainApp.java b/src/main/java/designPatterns/factory_pattern/MainApp.java similarity index 100% rename from src/designPatterns/factory_pattern/MainApp.java rename to src/main/java/designPatterns/factory_pattern/MainApp.java diff --git a/src/designPatterns/factory_pattern/Rectangle.java b/src/main/java/designPatterns/factory_pattern/Rectangle.java similarity index 100% rename from src/designPatterns/factory_pattern/Rectangle.java rename to src/main/java/designPatterns/factory_pattern/Rectangle.java diff --git a/src/designPatterns/factory_pattern/Shape.java b/src/main/java/designPatterns/factory_pattern/Shape.java similarity index 100% rename from src/designPatterns/factory_pattern/Shape.java rename to src/main/java/designPatterns/factory_pattern/Shape.java diff --git a/src/designPatterns/factory_pattern/ShapeFactory.java b/src/main/java/designPatterns/factory_pattern/ShapeFactory.java similarity index 100% rename from src/designPatterns/factory_pattern/ShapeFactory.java rename to src/main/java/designPatterns/factory_pattern/ShapeFactory.java diff --git a/src/designPatterns/factory_pattern/Square.java b/src/main/java/designPatterns/factory_pattern/Square.java similarity index 100% rename from src/designPatterns/factory_pattern/Square.java rename to src/main/java/designPatterns/factory_pattern/Square.java diff --git a/src/main/java/designPatterns/iterator_and_composite_pattern/TestDrive.java b/src/main/java/designPatterns/iterator_and_composite_pattern/TestDrive.java new file mode 100644 index 0000000..3ef3aaf --- /dev/null +++ b/src/main/java/designPatterns/iterator_and_composite_pattern/TestDrive.java @@ -0,0 +1,11 @@ +package designPatterns.iterator_and_composite_pattern; + +public class TestDrive { + + public static void main(String... args){ + System.out.println("Program started."); + + System.out.println("Program ended."); + } + +} diff --git a/src/designPatterns/chapter_2_observer_pattern/CoreFamily.java b/src/main/java/designPatterns/observer_pattern/CoreFamily.java similarity index 85% rename from src/designPatterns/chapter_2_observer_pattern/CoreFamily.java rename to src/main/java/designPatterns/observer_pattern/CoreFamily.java index 8b3091e..8a8036f 100644 --- a/src/designPatterns/chapter_2_observer_pattern/CoreFamily.java +++ b/src/main/java/designPatterns/observer_pattern/CoreFamily.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_2_observer_pattern; +package designPatterns.observer_pattern; public interface CoreFamily { public void registerRelative(Relative relative); diff --git a/src/designPatterns/chapter_2_observer_pattern/CoreFamilyImpl.java b/src/main/java/designPatterns/observer_pattern/CoreFamilyImpl.java similarity index 96% rename from src/designPatterns/chapter_2_observer_pattern/CoreFamilyImpl.java rename to src/main/java/designPatterns/observer_pattern/CoreFamilyImpl.java index 02c5605..9191883 100644 --- a/src/designPatterns/chapter_2_observer_pattern/CoreFamilyImpl.java +++ b/src/main/java/designPatterns/observer_pattern/CoreFamilyImpl.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_2_observer_pattern; +package designPatterns.observer_pattern; import java.util.ArrayList; import java.util.List; diff --git a/src/designPatterns/chapter_2_observer_pattern/ObserverPatternTestDrive.java b/src/main/java/designPatterns/observer_pattern/ObserverPatternTestDrive.java similarity index 95% rename from src/designPatterns/chapter_2_observer_pattern/ObserverPatternTestDrive.java rename to src/main/java/designPatterns/observer_pattern/ObserverPatternTestDrive.java index 7ef9298..68bfa3c 100644 --- a/src/designPatterns/chapter_2_observer_pattern/ObserverPatternTestDrive.java +++ b/src/main/java/designPatterns/observer_pattern/ObserverPatternTestDrive.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_2_observer_pattern; +package designPatterns.observer_pattern; /**NOTE: I didn't really implement the Observer pattern from Head First book here. * Just implemented the introduction part here. Could continue if interests arise in the future. - 10/04/2015*/ diff --git a/src/designPatterns/chapter_2_observer_pattern/Relative.java b/src/main/java/designPatterns/observer_pattern/Relative.java similarity index 73% rename from src/designPatterns/chapter_2_observer_pattern/Relative.java rename to src/main/java/designPatterns/observer_pattern/Relative.java index 3e62633..9ace511 100644 --- a/src/designPatterns/chapter_2_observer_pattern/Relative.java +++ b/src/main/java/designPatterns/observer_pattern/Relative.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_2_observer_pattern; +package designPatterns.observer_pattern; public interface Relative { public void update(String coreFamilyNames, int hikingTimes, int marriedMonths, String bibleReadingProgress); diff --git a/src/designPatterns/chapter_2_observer_pattern/RelativeImpl.java b/src/main/java/designPatterns/observer_pattern/RelativeImpl.java similarity index 95% rename from src/designPatterns/chapter_2_observer_pattern/RelativeImpl.java rename to src/main/java/designPatterns/observer_pattern/RelativeImpl.java index 30fdba9..bf08bea 100644 --- a/src/designPatterns/chapter_2_observer_pattern/RelativeImpl.java +++ b/src/main/java/designPatterns/observer_pattern/RelativeImpl.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_2_observer_pattern; +package designPatterns.observer_pattern; public class RelativeImpl implements Relative { diff --git a/src/main/java/designPatterns/proxy_pattern/TestDrive.java b/src/main/java/designPatterns/proxy_pattern/TestDrive.java new file mode 100644 index 0000000..b833fee --- /dev/null +++ b/src/main/java/designPatterns/proxy_pattern/TestDrive.java @@ -0,0 +1,11 @@ +package designPatterns.proxy_pattern; + +public class TestDrive { + + public static void main(String... args){ + System.out.println("Program started."); + + System.out.println("Program ended."); + } + +} diff --git a/src/main/java/designPatterns/singleton_pattern/TestDrive.java b/src/main/java/designPatterns/singleton_pattern/TestDrive.java new file mode 100644 index 0000000..8e0387c --- /dev/null +++ b/src/main/java/designPatterns/singleton_pattern/TestDrive.java @@ -0,0 +1,12 @@ +package designPatterns.singleton_pattern; + +public class TestDrive { + + public static void main(String... args){ + System.out.println("Program started."); + ThreadSafeSingleton threadSafeSingleton = ThreadSafeSingleton.getInstance(); + threadSafeSingleton.work(); + System.out.println("Program ended."); + } + +} diff --git a/src/main/java/designPatterns/singleton_pattern/ThreadSafeSingleton.java b/src/main/java/designPatterns/singleton_pattern/ThreadSafeSingleton.java new file mode 100644 index 0000000..272fc4d --- /dev/null +++ b/src/main/java/designPatterns/singleton_pattern/ThreadSafeSingleton.java @@ -0,0 +1,33 @@ +package designPatterns.singleton_pattern; + +/** + * Created by stevesun on 10/14/17. + */ +public class ThreadSafeSingleton { + + private static ThreadSafeSingleton instance; + + public static ThreadSafeSingleton getInstance() { + /** + * Double checked locking principle + * + * This is the most optimal approach in singleton pattern: + * https://www.journaldev.com/1377/java-singleton-design-pattern-best-practices-examples + * 1. It uses lazy initialization (saves resources, such as database connections.) + * 2. It's thread safe, but also minimizes performance penalty (minimizes the smallest code snippet possible, + * not synchronizing the whole method.) + * */ + if (instance == null) { + synchronized (ThreadSafeSingleton.class) { + if (instance == null) { + instance = new ThreadSafeSingleton(); + } + } + } + return instance; + } + + public static void work() { + System.out.println("One instance is here!!!"); + } +} diff --git a/src/main/java/designPatterns/state_pattern/TestDrive.java b/src/main/java/designPatterns/state_pattern/TestDrive.java new file mode 100644 index 0000000..25d88cc --- /dev/null +++ b/src/main/java/designPatterns/state_pattern/TestDrive.java @@ -0,0 +1,11 @@ +package designPatterns.state_pattern; + +public class TestDrive { + + public static void main(String... args){ + System.out.println("Program started."); + + System.out.println("Program ended."); + } + +} diff --git a/src/designPatterns/chapter_1_strategy_pattern/CookBehavior.java b/src/main/java/designPatterns/strategy_pattern/CookBehavior.java similarity index 52% rename from src/designPatterns/chapter_1_strategy_pattern/CookBehavior.java rename to src/main/java/designPatterns/strategy_pattern/CookBehavior.java index 6ab7449..ba8f055 100644 --- a/src/designPatterns/chapter_1_strategy_pattern/CookBehavior.java +++ b/src/main/java/designPatterns/strategy_pattern/CookBehavior.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_1_strategy_pattern; +package designPatterns.strategy_pattern; public interface CookBehavior { diff --git a/src/designPatterns/chapter_1_strategy_pattern/CookNoodlesBehavior.java b/src/main/java/designPatterns/strategy_pattern/CookNoodlesBehavior.java similarity index 76% rename from src/designPatterns/chapter_1_strategy_pattern/CookNoodlesBehavior.java rename to src/main/java/designPatterns/strategy_pattern/CookNoodlesBehavior.java index ed5ed14..ee13147 100644 --- a/src/designPatterns/chapter_1_strategy_pattern/CookNoodlesBehavior.java +++ b/src/main/java/designPatterns/strategy_pattern/CookNoodlesBehavior.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_1_strategy_pattern; +package designPatterns.strategy_pattern; public class CookNoodlesBehavior implements CookBehavior { diff --git a/src/designPatterns/chapter_1_strategy_pattern/CookRiceFlour.java b/src/main/java/designPatterns/strategy_pattern/CookRiceFlour.java similarity index 75% rename from src/designPatterns/chapter_1_strategy_pattern/CookRiceFlour.java rename to src/main/java/designPatterns/strategy_pattern/CookRiceFlour.java index 5b377de..2fb0245 100644 --- a/src/designPatterns/chapter_1_strategy_pattern/CookRiceFlour.java +++ b/src/main/java/designPatterns/strategy_pattern/CookRiceFlour.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_1_strategy_pattern; +package designPatterns.strategy_pattern; public class CookRiceFlour implements CookBehavior { diff --git a/src/designPatterns/chapter_1_strategy_pattern/LoveBehavior.java b/src/main/java/designPatterns/strategy_pattern/LoveBehavior.java similarity index 54% rename from src/designPatterns/chapter_1_strategy_pattern/LoveBehavior.java rename to src/main/java/designPatterns/strategy_pattern/LoveBehavior.java index 1757741..725e165 100644 --- a/src/designPatterns/chapter_1_strategy_pattern/LoveBehavior.java +++ b/src/main/java/designPatterns/strategy_pattern/LoveBehavior.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_1_strategy_pattern; +package designPatterns.strategy_pattern; public interface LoveBehavior { diff --git a/src/designPatterns/chapter_1_strategy_pattern/LoveHusbandBehavior.java b/src/main/java/designPatterns/strategy_pattern/LoveHusbandBehavior.java similarity index 77% rename from src/designPatterns/chapter_1_strategy_pattern/LoveHusbandBehavior.java rename to src/main/java/designPatterns/strategy_pattern/LoveHusbandBehavior.java index 814a9b7..6306686 100644 --- a/src/designPatterns/chapter_1_strategy_pattern/LoveHusbandBehavior.java +++ b/src/main/java/designPatterns/strategy_pattern/LoveHusbandBehavior.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_1_strategy_pattern; +package designPatterns.strategy_pattern; public class LoveHusbandBehavior implements LoveBehavior { diff --git a/src/designPatterns/chapter_1_strategy_pattern/ModelWife.java b/src/main/java/designPatterns/strategy_pattern/ModelWife.java similarity index 74% rename from src/designPatterns/chapter_1_strategy_pattern/ModelWife.java rename to src/main/java/designPatterns/strategy_pattern/ModelWife.java index 7e97c9e..20404a7 100644 --- a/src/designPatterns/chapter_1_strategy_pattern/ModelWife.java +++ b/src/main/java/designPatterns/strategy_pattern/ModelWife.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_1_strategy_pattern; +package designPatterns.strategy_pattern; public class ModelWife extends Wife { diff --git a/src/designPatterns/chapter_1_strategy_pattern/RealWife.java b/src/main/java/designPatterns/strategy_pattern/RealWife.java similarity index 62% rename from src/designPatterns/chapter_1_strategy_pattern/RealWife.java rename to src/main/java/designPatterns/strategy_pattern/RealWife.java index 3bb6299..7569e27 100644 --- a/src/designPatterns/chapter_1_strategy_pattern/RealWife.java +++ b/src/main/java/designPatterns/strategy_pattern/RealWife.java @@ -1,9 +1,10 @@ -package designPatterns.chapter_1_strategy_pattern; +package designPatterns.strategy_pattern; public class RealWife extends Wife { public RealWife() { - System.out.println("I'm the real wife - Sophie Yan! I'm Sophie Yan, the wife of Steve Sun, and I like cooking for my husband and family. "); + System.out.println("I'm the real wife - Sophie Yan! I'm Sophie Yan, " + + "the wife of Steve Sun, and I like cooking for my husband and family. "); this.cookBehavior = new CookRiceFlour(); this.loveBehavior = new LoveHusbandBehavior(); } diff --git a/src/designPatterns/chapter_1_strategy_pattern/StrategtyPatternTestDrive.java b/src/main/java/designPatterns/strategy_pattern/StrategtyPatternTestDrive.java similarity index 81% rename from src/designPatterns/chapter_1_strategy_pattern/StrategtyPatternTestDrive.java rename to src/main/java/designPatterns/strategy_pattern/StrategtyPatternTestDrive.java index f7689bc..914847a 100644 --- a/src/designPatterns/chapter_1_strategy_pattern/StrategtyPatternTestDrive.java +++ b/src/main/java/designPatterns/strategy_pattern/StrategtyPatternTestDrive.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_1_strategy_pattern; +package designPatterns.strategy_pattern; /** * The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. @@ -7,7 +7,8 @@ /**Design principle: * Favor composition over inheritance. * - * Not only does it let you encapsulate a family of algorithms into their own set of classes, but it also lets you change behavior at runtime.*/ + * Not only does it let you encapsulate a family of algorithms into their own set of classes, + * but it also lets you change behavior at runtime.*/ public class StrategtyPatternTestDrive { public static void main(String[] args) { diff --git a/src/designPatterns/chapter_1_strategy_pattern/Wife.java b/src/main/java/designPatterns/strategy_pattern/Wife.java similarity index 89% rename from src/designPatterns/chapter_1_strategy_pattern/Wife.java rename to src/main/java/designPatterns/strategy_pattern/Wife.java index a499278..6409bdc 100644 --- a/src/designPatterns/chapter_1_strategy_pattern/Wife.java +++ b/src/main/java/designPatterns/strategy_pattern/Wife.java @@ -1,4 +1,4 @@ -package designPatterns.chapter_1_strategy_pattern; +package designPatterns.strategy_pattern; public abstract class Wife { diff --git a/src/main/java/designPatterns/template_method_pattern/TestDrive.java b/src/main/java/designPatterns/template_method_pattern/TestDrive.java new file mode 100644 index 0000000..0d3605c --- /dev/null +++ b/src/main/java/designPatterns/template_method_pattern/TestDrive.java @@ -0,0 +1,11 @@ +package designPatterns.template_method_pattern; + +public class TestDrive { + + public static void main(String... args){ + System.out.println("Program started."); + + System.out.println("Program ended."); + } + +} diff --git a/src/designPatterns/visitor_pattern/Computer.java b/src/main/java/designPatterns/visitor_pattern/Computer.java similarity index 100% rename from src/designPatterns/visitor_pattern/Computer.java rename to src/main/java/designPatterns/visitor_pattern/Computer.java diff --git a/src/designPatterns/visitor_pattern/ComputerPart.java b/src/main/java/designPatterns/visitor_pattern/ComputerPart.java similarity index 100% rename from src/designPatterns/visitor_pattern/ComputerPart.java rename to src/main/java/designPatterns/visitor_pattern/ComputerPart.java diff --git a/src/designPatterns/visitor_pattern/ComputerPartDisplayVisitor.java b/src/main/java/designPatterns/visitor_pattern/ComputerPartDisplayVisitor.java similarity index 100% rename from src/designPatterns/visitor_pattern/ComputerPartDisplayVisitor.java rename to src/main/java/designPatterns/visitor_pattern/ComputerPartDisplayVisitor.java diff --git a/src/designPatterns/visitor_pattern/ComputerPartVisitor.java b/src/main/java/designPatterns/visitor_pattern/ComputerPartVisitor.java similarity index 100% rename from src/designPatterns/visitor_pattern/ComputerPartVisitor.java rename to src/main/java/designPatterns/visitor_pattern/ComputerPartVisitor.java diff --git a/src/designPatterns/visitor_pattern/Keyboard.java b/src/main/java/designPatterns/visitor_pattern/Keyboard.java similarity index 100% rename from src/designPatterns/visitor_pattern/Keyboard.java rename to src/main/java/designPatterns/visitor_pattern/Keyboard.java diff --git a/src/designPatterns/visitor_pattern/Monitor.java b/src/main/java/designPatterns/visitor_pattern/Monitor.java similarity index 100% rename from src/designPatterns/visitor_pattern/Monitor.java rename to src/main/java/designPatterns/visitor_pattern/Monitor.java diff --git a/src/designPatterns/visitor_pattern/Mouse.java b/src/main/java/designPatterns/visitor_pattern/Mouse.java similarity index 100% rename from src/designPatterns/visitor_pattern/Mouse.java rename to src/main/java/designPatterns/visitor_pattern/Mouse.java diff --git a/src/designPatterns/visitor_pattern/VisitorPatternDemo.java b/src/main/java/designPatterns/visitor_pattern/VisitorPatternDemo.java similarity index 100% rename from src/designPatterns/visitor_pattern/VisitorPatternDemo.java rename to src/main/java/designPatterns/visitor_pattern/VisitorPatternDemo.java diff --git a/src/main/java/encryption/EncryptionDecryption.java b/src/main/java/encryption/EncryptionDecryption.java new file mode 100644 index 0000000..e975f96 --- /dev/null +++ b/src/main/java/encryption/EncryptionDecryption.java @@ -0,0 +1,80 @@ +package encryption; + +import javax.crypto.*; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; +import javax.xml.bind.DatatypeConverter; +import java.security.AlgorithmParameters; +import java.security.SecureRandom; + +public class EncryptionDecryption { + /** + * This is a small program that uses Java native library to do encryption and description, + * credit: StackOverflow + */ + + private static String salt; + private static int iterations = 65536; + private static int keySize = 256; + private static byte[] ivBytes; + + private static SecretKey secretKey; + + public static void main(String[] args) throws Exception { + System.out.println("Program started."); + salt = getSalt(); + System.out.println("salt is: " + salt); + char[] message = "PasswordToEncrypt".toCharArray(); + System.out.println("Message: " + String.valueOf(message)); + System.out.println("Encrypted: " + encrypt(message)); + System.out.println("Decrypted: " + decrypt(encrypt(message).toCharArray())); + System.out.println("Program ended."); + } + + public static String encrypt(char[] plaintext) throws Exception { + byte[] saltBytes = salt.getBytes(); + + SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); + PBEKeySpec spec = new PBEKeySpec(plaintext, saltBytes, iterations, keySize); + secretKey = secretKeyFactory.generateSecret(spec); + SecretKeySpec secretSpec = new SecretKeySpec(secretKey.getEncoded(), "AES"); + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, secretSpec); + AlgorithmParameters algorithmParameters = cipher.getParameters(); + ivBytes = algorithmParameters.getParameterSpec(IvParameterSpec.class).getIV(); + byte[] encryptedTextBytes = cipher.doFinal(String.valueOf(plaintext).getBytes("UTF-8")); + + return DatatypeConverter.printBase64Binary(encryptedTextBytes); + } + + public static String decrypt(char[] encryptedText) throws Exception { + byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(new String(encryptedText)); + SecretKeySpec secretSpec = new SecretKeySpec(secretKey.getEncoded(), "AES"); + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, secretSpec, new IvParameterSpec(ivBytes)); + + byte[] decryptedTextBytes = null; + + try { + decryptedTextBytes = cipher.doFinal(encryptedTextBytes); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } + + return new String(decryptedTextBytes); + + } + + public static String getSalt() throws Exception { + //https://docs.oracle.com/en/java/javase/22/docs/specs/security/standard-names.html + SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");//this is the default algorithm, so can be omitted + byte[] salt = new byte[20]; + secureRandom.nextBytes(salt); + return new String(salt); + } +} diff --git a/src/main/java/encryption/SpringSecurityCryptoModule.java b/src/main/java/encryption/SpringSecurityCryptoModule.java new file mode 100644 index 0000000..71ba681 --- /dev/null +++ b/src/main/java/encryption/SpringSecurityCryptoModule.java @@ -0,0 +1,23 @@ +package encryption; + +import org.springframework.security.crypto.keygen.BytesKeyGenerator; +import org.springframework.security.crypto.keygen.KeyGenerators; + +public class SpringSecurityCryptoModule { + /** + * Reference: https://docs.spring.io/spring-security/site/docs/3.1.x/reference/crypto.html + */ + public static void main(String... args) { +// BytesEncryptor encryptor = Encryptors.standard("password", "salt"); + + String salt = KeyGenerators.string().generateKey(); // generates a random 8-byte salt that is then hex-encoded + System.out.println("salt is: " + salt); + +// TextEncryptor textEncryptor = Encryptors.text("password", "salt"); + + BytesKeyGenerator generator = KeyGenerators.secureRandom(); + byte[] key = generator.generateKey(); + System.out.println("key is: " + key); + + } +} diff --git a/src/sporadic/exceptionsCanBeSelfDefined/SteveSunException.java b/src/main/java/exceptionsCanBeSelfDefined/SteveSunException.java similarity index 93% rename from src/sporadic/exceptionsCanBeSelfDefined/SteveSunException.java rename to src/main/java/exceptionsCanBeSelfDefined/SteveSunException.java index 761f309..ab8ecef 100644 --- a/src/sporadic/exceptionsCanBeSelfDefined/SteveSunException.java +++ b/src/main/java/exceptionsCanBeSelfDefined/SteveSunException.java @@ -1,4 +1,4 @@ -package sporadic.exceptionsCanBeSelfDefined; +package exceptionsCanBeSelfDefined; /** * Base exception for all kinds of exceptions that I wrote myself for fun. diff --git a/src/sporadic/exceptionsCanBeSelfDefined/UnderstandExceptionTryCatch.java b/src/main/java/exceptionsCanBeSelfDefined/UnderstandExceptionTryCatch.java similarity index 97% rename from src/sporadic/exceptionsCanBeSelfDefined/UnderstandExceptionTryCatch.java rename to src/main/java/exceptionsCanBeSelfDefined/UnderstandExceptionTryCatch.java index 8836b87..367208e 100644 --- a/src/sporadic/exceptionsCanBeSelfDefined/UnderstandExceptionTryCatch.java +++ b/src/main/java/exceptionsCanBeSelfDefined/UnderstandExceptionTryCatch.java @@ -1,4 +1,4 @@ -package sporadic.exceptionsCanBeSelfDefined; +package exceptionsCanBeSelfDefined; /** * This is a simple program to help myself better understand what it really diff --git a/src/main/java/guice/AppInjector.java b/src/main/java/guice/AppInjector.java new file mode 100644 index 0000000..296ccfe --- /dev/null +++ b/src/main/java/guice/AppInjector.java @@ -0,0 +1,18 @@ +package guice; + +import com.google.inject.AbstractModule; + +/** + * Obviously google guice will not know which service to use, + * we have to configure it by extending AbstractModule abstract class + * and provide implementation for configure() method. + */ +public class AppInjector extends AbstractModule { + @Override protected void configure() { + //bind the service to implementation class +// bind(MessageService.class).to(EmailService.class); + + //bind MessageService to Facebook Message implementation + bind(MessageService.class).to(FacebookService.class); + } +} diff --git a/src/main/java/guice/ClientApplication.java b/src/main/java/guice/ClientApplication.java new file mode 100644 index 0000000..474520f --- /dev/null +++ b/src/main/java/guice/ClientApplication.java @@ -0,0 +1,17 @@ +package guice; + +import com.google.inject.Guice; +import com.google.inject.Injector; + +/** + * created by stevesun on 10/11/18/. + */ +public class ClientApplication { + public static void main(String[] args) { + Injector injector = Guice.createInjector(new AppInjector()); + + MyApplication app = injector.getInstance(MyApplication.class); + + app.sendMessage("Hi Steve", "fishercoder@gmail.com"); + } +} diff --git a/src/main/java/guice/EmailService.java b/src/main/java/guice/EmailService.java new file mode 100644 index 0000000..91c89d7 --- /dev/null +++ b/src/main/java/guice/EmailService.java @@ -0,0 +1,25 @@ +package guice; + +import javax.inject.Singleton; + +/** + * EmailService is one of the implementation of MessageService. Notice that class is annotated with + * @Singleton annotation. + * + * Since service objects will be created through injector classes, this annotation is provided + * to let them know that the service classes should be singleton objects. + * + * Google Guice 3.0 added the support for JSR-330 and we can use annotations from + * com.google.inject + * or + * javax.inject package. + */ + +@Singleton +public class EmailService implements MessageService { + @Override public boolean sendMessage(String msg, String receipient) { + //some fancy code to send email + System.out.println("Email Message sent to " + receipient + " with message=" + msg); + return true; + } +} diff --git a/src/main/java/guice/FacebookService.java b/src/main/java/guice/FacebookService.java new file mode 100644 index 0000000..3721197 --- /dev/null +++ b/src/main/java/guice/FacebookService.java @@ -0,0 +1,12 @@ +package guice; + +/** + * created by stevesun on 10/11/18/. + */ +public class FacebookService implements MessageService { + @Override public boolean sendMessage(String msg, String receipient) { + //some complex code to send Facebook message + System.out.println("Message sent to Facebook user "+receipient+" with message="+msg); + return true; + } +} diff --git a/src/main/java/guice/HelloWorldInGuice.java b/src/main/java/guice/HelloWorldInGuice.java new file mode 100644 index 0000000..befbbcc --- /dev/null +++ b/src/main/java/guice/HelloWorldInGuice.java @@ -0,0 +1,10 @@ +package guice; + +/** + * created by stevesun on 10/11/18/. + */ +public class HelloWorldInGuice { + public static void main(String... args) { + System.out.println("Hello world in Guice!"); + } +} diff --git a/src/main/java/guice/MessageService.java b/src/main/java/guice/MessageService.java new file mode 100644 index 0000000..90df8ef --- /dev/null +++ b/src/main/java/guice/MessageService.java @@ -0,0 +1,8 @@ +package guice; + +/** + * created by stevesun on 10/11/18/. + */ +public interface MessageService { + boolean sendMessage(String msg, String receipient); +} diff --git a/src/main/java/guice/MockMessageService.java b/src/main/java/guice/MockMessageService.java new file mode 100644 index 0000000..1d890a7 --- /dev/null +++ b/src/main/java/guice/MockMessageService.java @@ -0,0 +1,10 @@ +package guice; + +/** + * created by stevesun on 10/11/18/. + */ +public class MockMessageService implements MessageService { + @Override public boolean sendMessage(String msg, String receipient) { + return true; + } +} diff --git a/src/main/java/guice/MyApplication.java b/src/main/java/guice/MyApplication.java new file mode 100644 index 0000000..ddd7e77 --- /dev/null +++ b/src/main/java/guice/MyApplication.java @@ -0,0 +1,27 @@ +package guice; + +import javax.inject.Inject; + +/** + * This is our application class that consumes the service looks like below. + */ +public class MyApplication { + private MessageService service; + + // constructor based injector + @Inject + public MyApplication(MessageService svc){ + this.service=svc; + } + + //setter method injector + //@Inject + //public void setService(MessageService svc) { + // this.service = svc; + //} + + public boolean sendMessage(String msg, String rec) { + //some business logic here + return service.sendMessage(msg, rec); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_1_simple_binding_example/MainApp.java b/src/main/java/guice/relearn_2019_09/_1_simple_binding_example/MainApp.java new file mode 100644 index 0000000..bf2f5fa --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_1_simple_binding_example/MainApp.java @@ -0,0 +1,33 @@ +package guice.relearn_2019_09._1_simple_binding_example; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import guice.relearn_2019_09._2_named_annotation_example.TextEditor; +import guice.relearn_2019_09._2_named_annotation_example.TextEditorModule; + +/** + * An injector is the object-graph builder + * and a Module is its core building block. + * Thus, the first step is to create an injector and then use the injector to get the objects. + * + * + * In the this example, + * TextEditor class object graph is constructed by Guice and + * this graph contains TextEditor object and its dependency as WinWordSpellChecker object.*/ +public class MainApp { + public static void main(String[] args) { + /* + * Guice.createInjector() takes Modules, and returns a new Injector + * instance. This method is to be called once during application startup. + */ + + Injector injector = Guice.createInjector(new TextEditorModule()); + /* + * Build object using injector + */ + TextEditor textEditor = injector.getInstance(TextEditor.class); + textEditor.makeConnection(); + + System.out.println("textEditor is instantiated."); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_1_simple_binding_example/SpellChecker.java b/src/main/java/guice/relearn_2019_09/_1_simple_binding_example/SpellChecker.java new file mode 100644 index 0000000..7145329 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_1_simple_binding_example/SpellChecker.java @@ -0,0 +1,5 @@ +package guice.relearn_2019_09._1_simple_binding_example; + +public interface SpellChecker { + void checkSpelling(); +} diff --git a/src/main/java/guice/relearn_2019_09/_1_simple_binding_example/TextEditor.java b/src/main/java/guice/relearn_2019_09/_1_simple_binding_example/TextEditor.java new file mode 100644 index 0000000..b09efd5 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_1_simple_binding_example/TextEditor.java @@ -0,0 +1,28 @@ +package guice.relearn_2019_09._1_simple_binding_example; + +import javax.inject.Inject; + +public class TextEditor { + private SpellChecker spellChecker; + + /**Consider you have an application which has a text editor component and you want to provide a spell check. Your standard code would look something like this. + * Note that here we have created a dependency between the TextEditor and the SpellChecker.*/ +// public TextEditor() { +// spellChecker = new SpellChecker(); +// } + + /** + * In an inversion of control scenario, we would instead do something like this: + *

+ * Here, the TextEditor should not worry about SpellChecker implementation. + * The SpellChecker will be implemented independently and will be provided to the TextEditor at the time of TextEditor instantiation. + */ + @Inject + public TextEditor(SpellChecker spellChecker) { + this.spellChecker = spellChecker; + } + + public void makeSpellCheck() { + spellChecker.checkSpelling(); + } +} \ No newline at end of file diff --git a/src/main/java/guice/relearn_2019_09/_1_simple_binding_example/TextEditorModule.java b/src/main/java/guice/relearn_2019_09/_1_simple_binding_example/TextEditorModule.java new file mode 100644 index 0000000..64f16ca --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_1_simple_binding_example/TextEditorModule.java @@ -0,0 +1,20 @@ +package guice.relearn_2019_09._1_simple_binding_example; + +import com.google.inject.AbstractModule; + +/** + * Dependency Injection is controlled by the Guice Bindings. + * Guice uses bindings to map object types to their actual implementations. + * These bindings are defined a module. + * A module is a collection of bindings as shown below − + * */ +public class TextEditorModule extends AbstractModule { + @Override + protected void configure() { + /* + * Bind SpellChecker binding to WinWordSpellChecker implementation + * whenever spellChecker dependency is used. + */ + bind(SpellChecker.class).to(WinWordSpellChecker.class); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_1_simple_binding_example/WinWordSpellChecker.java b/src/main/java/guice/relearn_2019_09/_1_simple_binding_example/WinWordSpellChecker.java new file mode 100644 index 0000000..e4e85b1 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_1_simple_binding_example/WinWordSpellChecker.java @@ -0,0 +1,8 @@ +package guice.relearn_2019_09._1_simple_binding_example; + +public class WinWordSpellChecker implements SpellChecker { + @Override + public void checkSpelling() { + System.out.println("Inside checkSpelling implementation." ); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_2_named_annotation_example/MainApp.java b/src/main/java/guice/relearn_2019_09/_2_named_annotation_example/MainApp.java new file mode 100644 index 0000000..925b2a6 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_2_named_annotation_example/MainApp.java @@ -0,0 +1,31 @@ +package guice.relearn_2019_09._2_named_annotation_example; + +import com.google.inject.Guice; +import com.google.inject.Injector; + +/** + * An injector is the object-graph builder + * and a Module is its core building block. + * Thus, the first step is to create an injector and then use the injector to get the objects. + * + * + * In the this example, + * TextEditor class object graph is constructed by Guice and + * this graph contains TextEditor object and its dependency as WinWordSpellChecker object.*/ +public class MainApp { + public static void main(String[] args) { + /* + * Guice.createInjector() takes Modules, and returns a new Injector + * instance. This method is to be called once during application startup. + */ + + Injector injector = Guice.createInjector(new TextEditorModule()); + /* + * Build object using injector + */ + TextEditor textEditor = injector.getInstance(TextEditor.class); + textEditor.makeConnection(); + + System.out.println("textEditor is instantiated."); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_2_named_annotation_example/SpellChecker.java b/src/main/java/guice/relearn_2019_09/_2_named_annotation_example/SpellChecker.java new file mode 100644 index 0000000..6b878ea --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_2_named_annotation_example/SpellChecker.java @@ -0,0 +1,5 @@ +package guice.relearn_2019_09._2_named_annotation_example; + +public interface SpellChecker { + void checkSpelling(); +} diff --git a/src/main/java/guice/relearn_2019_09/_2_named_annotation_example/TextEditor.java b/src/main/java/guice/relearn_2019_09/_2_named_annotation_example/TextEditor.java new file mode 100644 index 0000000..f08a32c --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_2_named_annotation_example/TextEditor.java @@ -0,0 +1,21 @@ +package guice.relearn_2019_09._2_named_annotation_example; + +import javax.inject.Inject; +import javax.inject.Named; + +public class TextEditor { + /** + * Inject using @Named annotation + * + * This can be achived using toInstance() method.*/ + private String dbUrl; + + @Inject + public TextEditor(@Named("JDBC") String dbUrl) { + this.dbUrl = dbUrl; + } + + public void makeConnection() { + System.out.println(dbUrl); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_2_named_annotation_example/TextEditorModule.java b/src/main/java/guice/relearn_2019_09/_2_named_annotation_example/TextEditorModule.java new file mode 100644 index 0000000..0d0bac2 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_2_named_annotation_example/TextEditorModule.java @@ -0,0 +1,21 @@ +package guice.relearn_2019_09._2_named_annotation_example; + +import com.google.inject.AbstractModule; +import com.google.inject.name.Names; + +/** + * Dependency Injection is controlled by the Guice Bindings. + * Guice uses bindings to map object types to their actual implementations. + * These bindings are defined a module. + * A module is a collection of bindings as shown below − + * */ +public class TextEditorModule extends AbstractModule { + @Override + protected void configure() { + /* + * Bind SpellChecker binding to WinWordSpellChecker implementation + * whenever spellChecker dependency is used. + */ + bind(String.class).annotatedWith(Names.named("JDBC")).toInstance("jdbc:mysql://localhost:5326/emp"); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_2_named_annotation_example/WinWordSpellChecker.java b/src/main/java/guice/relearn_2019_09/_2_named_annotation_example/WinWordSpellChecker.java new file mode 100644 index 0000000..cfa504f --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_2_named_annotation_example/WinWordSpellChecker.java @@ -0,0 +1,8 @@ +package guice.relearn_2019_09._2_named_annotation_example; + +public class WinWordSpellChecker implements SpellChecker { + @Override + public void checkSpelling() { + System.out.println("Inside checkSpelling implementation." ); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_3_provides_annotation_example/GuiceTester.java b/src/main/java/guice/relearn_2019_09/_3_provides_annotation_example/GuiceTester.java new file mode 100644 index 0000000..30576f1 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_3_provides_annotation_example/GuiceTester.java @@ -0,0 +1,83 @@ +package guice.relearn_2019_09._3_provides_annotation_example; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Provides; + +import javax.inject.Inject; + +/** + * Guice provides a way to create bindings with complex objects using @provides method. + * + * This method is being part of Binding Module and provides the complex object to be mapped. + * + * See the complete example below.*/ +public class GuiceTester { + public static void main(String[] args) { + Injector injector = Guice.createInjector(new TextEditorModule()); + TextEditor editor = injector.getInstance(TextEditor.class); + editor.makeSpellCheck(); + System.out.println("Program ended."); + } +} + +class TextEditor { + private SpellChecker spellChecker; + + @Inject + public TextEditor(SpellChecker spellChecker) { + this.spellChecker = spellChecker; + } + + public void makeSpellCheck() { + spellChecker.checkSpelling(); + } +} + +//Binding Module +class TextEditorModule extends AbstractModule { + @Override + protected void configure() { + } + + @Provides + public SpellChecker provideSpellChecker() { + String dbUrl = "jdbc:mysql://localhost:5326/emp"; + String user = "user"; + int timeout = 100; + + SpellChecker SpellChecker = new SpellCheckerImpl(dbUrl, user, timeout); + return SpellChecker; + } +} + +//spell checker interface +interface SpellChecker { + public void checkSpelling(); +} + +//spell checker implementation +class SpellCheckerImpl implements SpellChecker { + + private String dbUrl; + private String user; + private Integer timeout; + + @Inject + public SpellCheckerImpl(String dbUrl, + String user, + Integer timeout) { + this.dbUrl = dbUrl; + this.user = user; + this.timeout = timeout; + } + + @Override + public void checkSpelling() { + System.out.println("Inside checkSpelling."); + System.out.println(dbUrl); + System.out.println(user); + System.out.println(timeout); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_4_provider_class_example/GuiceTester.java b/src/main/java/guice/relearn_2019_09/_4_provider_class_example/GuiceTester.java new file mode 100644 index 0000000..c5305eb --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_4_provider_class_example/GuiceTester.java @@ -0,0 +1,84 @@ +package guice.relearn_2019_09._4_provider_class_example; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Provider; + +import javax.inject.Inject; + +/** + * As @provides method becomes more complex, this method can be moved to separate classes using Provider interface. + * */ +public class GuiceTester { + public static void main(String[] args) { + Injector injector = Guice.createInjector(new TextEditorModule()); + TextEditor editor = injector.getInstance(TextEditor.class); + editor.makeSpellCheck(); + System.out.println("Program ended."); + } +} + +class TextEditor { + private SpellChecker spellChecker; + + @Inject + public TextEditor(SpellChecker spellChecker) { + this.spellChecker = spellChecker; + } + + public void makeSpellCheck() { + spellChecker.checkSpelling(); + } +} + +//Binding Module +class TextEditorModule extends AbstractModule { + /**you have to map the provider to type.*/ + @Override + protected void configure() { + bind(SpellChecker.class).toProvider(SpellCheckerProvider.class); + } +} + +//spell checker interface +interface SpellChecker { + public void checkSpelling(); +} + +//spell checker implementation +class SpellCheckerImpl implements SpellChecker { + + private String dbUrl; + private String user; + private Integer timeout; + + @Inject + public SpellCheckerImpl(String dbUrl, + String user, + Integer timeout) { + this.dbUrl = dbUrl; + this.user = user; + this.timeout = timeout; + } + + @Override + public void checkSpelling() { + System.out.println("Inside checkSpelling."); + System.out.println(dbUrl); + System.out.println(user); + System.out.println(timeout); + } +} + +class SpellCheckerProvider implements Provider { + @Override + public SpellChecker get() { + String dbUrl = "jdbc:mysql://localhost:5326/emp"; + String user = "user"; + int timeout = 100; + + SpellChecker SpellChecker = new SpellCheckerImpl(dbUrl, user, timeout); + return SpellChecker; + } +} diff --git a/src/main/java/guice/relearn_2019_09/_5_constructor_binding_example/GuiceTester.java b/src/main/java/guice/relearn_2019_09/_5_constructor_binding_example/GuiceTester.java new file mode 100644 index 0000000..465f239 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_5_constructor_binding_example/GuiceTester.java @@ -0,0 +1,71 @@ +package guice.relearn_2019_09._5_constructor_binding_example; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.name.Named; +import com.google.inject.name.Names; + +/** + * Guice provides a way to create bindings with specific constructor of an object using toConstructor() method. + */ +public class GuiceTester { + public static void main(String[] args) { + Injector injector = Guice.createInjector(new TextEditorModule()); + TextEditor editor = injector.getInstance(TextEditor.class); + editor.makeSpellCheck(); + } +} + +class TextEditor { + private SpellChecker spellChecker; + + @Inject + public TextEditor(SpellChecker spellChecker) { + this.spellChecker = spellChecker; + } + + public void makeSpellCheck() { + spellChecker.checkSpelling(); + } +} + +//Binding Module +class TextEditorModule extends AbstractModule { + @Override + protected void configure() { + try { + bind(SpellChecker.class).toConstructor(SpellCheckerImpl.class.getConstructor(String.class)); + } catch (NoSuchMethodException | SecurityException e) { + System.out.println("Required constructor missing"); + } + + bind(String.class).annotatedWith(Names.named("JDBC")).toInstance("jdbc:mysql://localhost:5326/emp"); + } +} + +//spell checker interface +interface SpellChecker { + public void checkSpelling(); +} + +//spell checker implementation +class SpellCheckerImpl implements SpellChecker { + private String dbUrl; + + public SpellCheckerImpl() { + System.out.println("In default constructor."); + } + + public SpellCheckerImpl(@Named("JDBC") String dbUrl) { + this.dbUrl = dbUrl; + System.out.println("In constructor with a string param."); + } + + @Override + public void checkSpelling() { + System.out.println("Inside checkSpelling."); + System.out.println(dbUrl); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_6_method_injection_example/GuiceTester.java b/src/main/java/guice/relearn_2019_09/_6_method_injection_example/GuiceTester.java new file mode 100644 index 0000000..e649cb4 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_6_method_injection_example/GuiceTester.java @@ -0,0 +1,72 @@ +package guice.relearn_2019_09._6_method_injection_example; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.ImplementedBy; +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.name.Named; +import com.google.inject.name.Names; + +/** + * Injection is a process of injecting dependency into an object. + * Method injection is used to set value object as dependency to the object. + * + * Observe the example given below. + * */ +public class GuiceTester { + public static void main(String[] args) { + Injector injector = Guice.createInjector(new TextEditorModule()); + TextEditor editor = injector.getInstance(TextEditor.class); + editor.makeSpellCheck(); + System.out.println("Program ended."); + } +} + +class TextEditor { + private SpellChecker spellChecker; + + @Inject + public TextEditor(SpellChecker spellChecker) { + this.spellChecker = spellChecker; + } + + public void makeSpellCheck() { + spellChecker.checkSpelling(); + } +} + +//Binding Module +class TextEditorModule extends AbstractModule { + @Override + protected void configure() { + bind(String.class) + .annotatedWith(Names.named("JDBC")) + .toInstance("jdbc:mysql://localhost:5326/emp"); + } +} + +@ImplementedBy(SpellCheckerImpl.class) +interface SpellChecker { + public void checkSpelling(); +} + +//spell checker implementation +class SpellCheckerImpl implements SpellChecker { + private String dbUrl; + + public SpellCheckerImpl() { + } + + //the method name does not impact injection + @Inject + public void helloWorldSetDbUrl(@Named("JDBC") String dbUrl) { + this.dbUrl = dbUrl; + } + + @Override + public void checkSpelling() { + System.out.println("Inside checkSpelling."); + System.out.println(dbUrl); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_7_scope_example/GuiceTester.java b/src/main/java/guice/relearn_2019_09/_7_scope_example/GuiceTester.java new file mode 100644 index 0000000..8d47369 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_7_scope_example/GuiceTester.java @@ -0,0 +1,89 @@ +package guice.relearn_2019_09._7_scope_example; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.Singleton; + +import static org.junit.Assert.assertEquals; + +/** + * Guice returns a new instance every time it supplies a value as its DEFAULT behavior. + * It is configurable via scopes. The various scopes that Guice supports are − + * + * @Singleton − Single instance for lifetime of the application. @Singleton object needs to be threadsafe. + * @SessionScoped − Single instance for a particular session of the web application. @SessionScoped object needs to be threadsafe. + * @RequestScoped − Single instance for a particular request of the web application. @RequestScoped object does not need to be threadsafe. + */ +public class GuiceTester { + public static void main(String[] args) { + Injector injector = Guice.createInjector(new TextEditorModule()); + SpellChecker spellChecker = new SpellCheckerImpl(); + injector.injectMembers(spellChecker); + + TextEditor editor = injector.getInstance(TextEditor.class); + double id = editor.getSpellCheckerId(); + System.out.println(id); + + TextEditor editor1 = injector.getInstance(TextEditor.class); + double id1 = editor1.getSpellCheckerId(); + System.out.println(id1); + + /**Because it's a singleton, so these two values will be the same.*/ + assertEquals(0, id, id1); + } +} + +class TextEditor { + private SpellChecker spellChecker; + + @Inject + public void setSpellChecker(SpellChecker spellChecker) { + this.spellChecker = spellChecker; + } + + public TextEditor() { + } + + public void makeSpellCheck() { + spellChecker.checkSpelling(); + } + + public double getSpellCheckerId() { + return spellChecker.getId(); + } +} + +//Binding Module +class TextEditorModule extends AbstractModule { + @Override + protected void configure() { + bind(SpellChecker.class).to(SpellCheckerImpl.class); + } +} + +interface SpellChecker { + public double getId(); + + public void checkSpelling(); +} + +@Singleton +class SpellCheckerImpl implements SpellChecker { + double id; + + public SpellCheckerImpl() { + id = Math.random(); + } + + @Override + public void checkSpelling() { + System.out.println("Inside checkSpelling."); + } + + @Override + public double getId() { + return id; + } +} diff --git a/src/main/java/guice/relearn_2019_09/_8_already_configured_exception/PrivateModuleTest.java b/src/main/java/guice/relearn_2019_09/_8_already_configured_exception/PrivateModuleTest.java new file mode 100644 index 0000000..9a69a98 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_8_already_configured_exception/PrivateModuleTest.java @@ -0,0 +1,540 @@ +package guice.relearn_2019_09._8_already_configured_exception; + +import com.google.inject.*; +import com.google.inject.name.Named; +import com.google.inject.name.Names; +import com.google.inject.spi.ExposedBinding; +import com.google.inject.util.Types; +import junit.framework.TestCase; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static com.google.inject.name.Names.named; + +public class PrivateModuleTest extends TestCase { + + public void testBasicUsage() { + Injector injector = Guice.createInjector(new AbstractModule() { + @Override protected void configure() { + bind(String.class).annotatedWith(named("a")).toInstance("public"); + + install(new PrivateModule() { + @Override public void configure() { + bind(String.class).annotatedWith(named("b")).toInstance("i"); + + bind(AB.class).annotatedWith(named("one")).to(AB.class); + expose(AB.class).annotatedWith(named("one")); + } + }); + + install(new PrivateModule() { + @Override public void configure() { + bind(String.class).annotatedWith(named("b")).toInstance("ii"); + + bind(AB.class).annotatedWith(named("two")).to(AB.class); + expose(AB.class).annotatedWith(named("two")); + } + }); + } + }); + + AB ab1 = injector.getInstance(Key.get(AB.class, named("one"))); + assertEquals("public", ab1.a); + assertEquals("i", ab1.b); + + AB ab2 = injector.getInstance(Key.get(AB.class, named("two"))); + assertEquals("public", ab2.a); + assertEquals("ii", ab2.b); + } + + public void testWithoutPrivateModules() { + Injector injector = Guice.createInjector(new AbstractModule() { + @Override protected void configure() { + PrivateBinder bindA = binder().newPrivateBinder(); + bindA.bind(String.class).annotatedWith(named("a")).toInstance("i"); + bindA.expose(String.class).annotatedWith(named("a")); + bindA.bind(String.class).annotatedWith(named("c")).toInstance("private to A"); + + PrivateBinder bindB = binder().newPrivateBinder(); + bindB.bind(String.class).annotatedWith(named("b")).toInstance("ii"); + bindB.expose(String.class).annotatedWith(named("b")); + bindB.bind(String.class).annotatedWith(named("c")).toInstance("private to B"); + } + }); + + assertEquals("i", injector.getInstance(Key.get(String.class, named("a")))); + assertEquals("ii", injector.getInstance(Key.get(String.class, named("b")))); + } + + public void testMisplacedExposedAnnotation() { + try { + Guice.createInjector(new AbstractModule() { + @Override protected void configure() {} + + @Provides + @Exposed + String provideString() { + return "i"; + } + }); + fail(); + } catch (CreationException expected) { + System.out.println(expected.getMessage() + "Cannot expose java.lang.String on a standard binder. " + + "Exposed bindings are only applicable to private binders." + + " at " + PrivateModuleTest.class.getName() + "provideString(PrivateModuleTest.java:"); + } + } + + public void testMisplacedExposeStatement() { + try { + Guice.createInjector(new AbstractModule() { + @Override protected void configure() { + ((PrivateBinder) binder()).expose(String.class).annotatedWith(named("a")); + } + }); + fail(); + } catch (CreationException expected) { + System.out.println(expected.getMessage() + "Cannot expose java.lang.String on a standard binder. " + + "Exposed bindings are only applicable to private binders." + + " at " + PrivateModuleTest.class.getName() + getClass()); + } + } + + public void testPrivateModulesAndProvidesMethods() { + Injector injector = Guice.createInjector(new AbstractModule() { + @Override protected void configure() { + install(new PrivateModule() { + @Override public void configure() { + expose(String.class).annotatedWith(named("a")); + } + + @Provides @Named("a") String providePublicA() { + return "i"; + } + + @Provides @Named("b") String providePrivateB() { + return "private"; + } + }); + + install(new PrivateModule() { + @Override public void configure() {} + + @Provides @Named("c") String providePrivateC() { + return "private"; + } + + @Provides @Exposed @Named("d") String providePublicD() { + return "ii"; + } + }); + } + }); + + assertEquals("i", injector.getInstance(Key.get(String.class, named("a")))); + + try { + injector.getInstance(Key.get(String.class, named("b"))); + fail(); + } catch(ConfigurationException expected) { + } + + try { + injector.getInstance(Key.get(String.class, named("c"))); + fail(); + } catch(ConfigurationException expected) { + } + + assertEquals("ii", injector.getInstance(Key.get(String.class, named("d")))); + } + + public void testCannotBindAKeyExportedByASibling() { + try { + Guice.createInjector(new AbstractModule() { + @Override protected void configure() { + install(new PrivateModule() { + @Override public void configure() { + bind(String.class).toInstance("public"); + expose(String.class); + } + }); + + install(new PrivateModule() { + @Override public void configure() { + bind(String.class).toInstance("private"); + } + }); + } + }); + fail(); + } catch (CreationException expected) { +// assertContains(expected.getMessage(), +// "A binding to java.lang.String was already configured at ", +// getClass().getName(), getDeclaringSourcePart(getClass()), +// " at " + getClass().getName(), getDeclaringSourcePart(getClass())); + } + } + + public void testExposeButNoBind() { + try { + Guice.createInjector(new AbstractModule() { + @Override protected void configure() { + bind(String.class).annotatedWith(named("a")).toInstance("a"); + bind(String.class).annotatedWith(named("b")).toInstance("b"); + + install(new PrivateModule() { + @Override public void configure() { + expose(AB.class); + } + }); + } + }); + fail("AB was exposed but not bound"); + } catch (CreationException expected) { +// assertContains(expected.getMessage(), +// "Could not expose() " + AB.class.getName() + ", it must be explicitly bound", +// getDeclaringSourcePart(getClass())); + } + } + + /** + * Ensure that when we've got errors in different private modules, Guice presents all errors + * in a unified message. + */ + public void testMessagesFromPrivateModulesAreNicelyIntegrated() { + try { + Guice.createInjector( + new PrivateModule() { + @Override public void configure() { + bind(C.class); + } + }, + new PrivateModule() { + @Override public void configure() { + bind(AB.class); + } + } + ); + fail(); + } catch (CreationException expected) { +// assertContains(expected.getMessage(), +// "1) No implementation for " + C.class.getName() + " was bound.", +// "at " + getClass().getName(), getDeclaringSourcePart(getClass()), +// "2) No implementation for " + String.class.getName(), "Named(value=a) was bound.", +// "for field at " + AB.class.getName() + ".a(PrivateModuleTest.java:", +// "3) No implementation for " + String.class.getName(), "Named(value=b) was bound.", +// "for field at " + AB.class.getName() + ".b(PrivateModuleTest.java:", +// "3 errors"); + } + } + + public void testNestedPrivateInjectors() { + Injector injector = Guice.createInjector(new PrivateModule() { + @Override public void configure() { + expose(String.class); + + install(new PrivateModule() { + @Override public void configure() { + bind(String.class).toInstance("nested"); + expose(String.class); + } + }); + } + }); + + assertEquals("nested", injector.getInstance(String.class)); + } + + public void testInstallingRegularModulesFromPrivateModules() { + Injector injector = Guice.createInjector(new PrivateModule() { + @Override public void configure() { + expose(String.class); + + install(new AbstractModule() { + @Override protected void configure() { + bind(String.class).toInstance("nested"); + } + }); + } + }); + + assertEquals("nested", injector.getInstance(String.class)); + } + + public void testNestedPrivateModulesWithSomeKeysUnexposed() { + Injector injector = Guice.createInjector(new PrivateModule() { + @Override public void configure() { + bind(String.class).annotatedWith(named("bound outer, exposed outer")).toInstance("boeo"); + expose(String.class).annotatedWith(named("bound outer, exposed outer")); + bind(String.class).annotatedWith(named("bound outer, exposed none")).toInstance("boen"); + expose(String.class).annotatedWith(named("bound inner, exposed both")); + + install(new PrivateModule() { + @Override public void configure() { + bind(String.class).annotatedWith(named("bound inner, exposed both")).toInstance("bieb"); + expose(String.class).annotatedWith(named("bound inner, exposed both")); + bind(String.class).annotatedWith(named("bound inner, exposed none")).toInstance("bien"); + } + }); + } + }); + + assertEquals("boeo", + injector.getInstance(Key.get(String.class, named("bound outer, exposed outer")))); + assertEquals("bieb", + injector.getInstance(Key.get(String.class, named("bound inner, exposed both")))); + + try { + injector.getInstance(Key.get(String.class, named("bound outer, exposed none"))); + fail(); + } catch (ConfigurationException expected) { + } + + try { + injector.getInstance(Key.get(String.class, named("bound inner, exposed none"))); + fail(); + } catch (ConfigurationException expected) { + } + } + + public void testDependenciesBetweenPrivateAndPublic() { + Injector injector = Guice.createInjector( + new PrivateModule() { + @Override protected void configure() {} + + @Provides @Exposed @Named("a") String provideA() { + return "A"; + } + + @Provides @Exposed @Named("abc") String provideAbc(@Named("ab") String ab) { + return ab + "C"; + } + }, + new AbstractModule() { + @Override protected void configure() {} + + @Provides @Named("ab") String provideAb(@Named("a") String a) { + return a + "B"; + } + + @Provides @Named("abcd") String provideAbcd(@Named("abc") String abc) { + return abc + "D"; + } + } + ); + + assertEquals("ABCD", injector.getInstance(Key.get(String.class, named("abcd")))); + } + + public void testDependenciesBetweenPrivateAndPublicWithPublicEagerSingleton() { + Injector injector = Guice.createInjector( + new PrivateModule() { + @Override protected void configure() {} + + @Provides @Exposed @Named("a") String provideA() { + return "A"; + } + + @Provides @Exposed @Named("abc") String provideAbc(@Named("ab") String ab) { + return ab + "C"; + } + }, + new AbstractModule() { + @Override protected void configure() { + bind(String.class).annotatedWith(named("abcde")).toProvider(new Provider() { + @Inject @Named("abcd") String abcd; + + public String get() { + return abcd + "E"; + } + }).asEagerSingleton(); + } + + @Provides @Named("ab") String provideAb(@Named("a") String a) { + return a + "B"; + } + + @Provides @Named("abcd") String provideAbcd(@Named("abc") String abc) { + return abc + "D"; + } + } + ); + + assertEquals("ABCDE", injector.getInstance(Key.get(String.class, named("abcde")))); + } + + public void testDependenciesBetweenPrivateAndPublicWithPrivateEagerSingleton() { + Injector injector = Guice.createInjector( + new AbstractModule() { + @Override protected void configure() {} + + @Provides @Named("ab") String provideAb(@Named("a") String a) { + return a + "B"; + } + + @Provides @Named("abcd") String provideAbcd(@Named("abc") String abc) { + return abc + "D"; + } + }, + new PrivateModule() { + @Override protected void configure() { + bind(String.class).annotatedWith(named("abcde")).toProvider(new Provider() { + @Inject @Named("abcd") String abcd; + + public String get() { + return abcd + "E"; + } + }).asEagerSingleton(); + expose(String.class).annotatedWith(named("abcde")); + } + + @Provides @Exposed @Named("a") String provideA() { + return "A"; + } + + @Provides @Exposed @Named("abc") String provideAbc(@Named("ab") String ab) { + return ab + "C"; + } + } + ); + + assertEquals("ABCDE", injector.getInstance(Key.get(String.class, named("abcde")))); + } + + static class AB { + @Inject @Named("a") String a; + @Inject @Named("b") String b; + } + + interface C {} + + public void testSpiAccess() { + Injector injector = Guice.createInjector(new PrivateModule() { + @Override public void configure() { + bind(String.class).annotatedWith(named("a")).toInstance("private"); + bind(String.class).annotatedWith(named("b")).toInstance("exposed"); + expose(String.class).annotatedWith(named("b")); + } + }); + + ExposedBinding binding + = (ExposedBinding) injector.getBinding(Key.get(String.class, Names.named("b"))); +// assertEquals(ImmutableSet..", +// "It was already configured on one or more child injectors or private modules", +// "bound at " + FailingPrivateModule.class.getName() + ".configure(", +// asModuleChain(ManyPrivateModules.class, FailingPrivateModule.class), +// "bound at " + SecondFailingPrivateModule.class.getName() + ".configure(", +// asModuleChain(ManyPrivateModules.class, SecondFailingPrivateModule.class), +// "If it was in a PrivateModule, did you forget to expose the binding?", +// "while locating com.google.inject.Provider"); + } + } + + public void testParentBindingToPrivateJitBinding() { + Injector injector = Guice.createInjector(new ManyPrivateModules()); + try { + injector.getBinding(PrivateFoo.class); + fail(); + } catch(ConfigurationException expected) { + assertEquals(1, expected.getErrorMessages().size()); +// assertContains(expected.toString(), +// "Unable to create binding for " + PrivateFoo.class.getName(), +// "It was already configured on one or more child injectors or private modules", +// "(bound by a just-in-time binding)", +// "If it was in a PrivateModule, did you forget to expose the binding?", +// "while locating " + PrivateFoo.class.getName()); + } + } + + private static class FailingModule extends AbstractModule { + @Override protected void configure() { + bind(Collection.class).to(List.class); + install(new ManyPrivateModules()); + } + } + + private static class ManyPrivateModules extends AbstractModule { + @Override protected void configure() { + // make sure duplicate sources are collapsed + install(new FailingPrivateModule()); + install(new FailingPrivateModule()); + // but additional sources are listed + install(new SecondFailingPrivateModule()); + } + } + + private static class FailingPrivateModule extends PrivateModule { + @Override protected void configure() { + bind(List.class).toInstance(new ArrayList()); + + // Add the Provider binding, created just-in-time, + // to make sure our linked JIT bindings have the correct source. + getProvider(Key.get(Types.providerOf(List.class))); + + // Request a JIT binding for PrivateFoo, which can only + // be created in the private module because it depends + // on List. + getProvider(PrivateFoo.class); + } + } + + /** A second class, so we can see another name in the source list. */ + private static class SecondFailingPrivateModule extends PrivateModule { + @Override protected void configure() { + bind(List.class).toInstance(new ArrayList()); + + // Add the Provider binding, created just-in-time, + // to make sure our linked JIT bindings have the correct source. + getProvider(Key.get(Types.providerOf(List.class))); + + // Request a JIT binding for PrivateFoo, which can only + // be created in the private module because it depends + // on List. + getProvider(PrivateFoo.class); + } + } + + private static class PrivateFoo { + @Inject List list; + } +} diff --git a/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/AmazonDynamoDB.java b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/AmazonDynamoDB.java new file mode 100644 index 0000000..e489c6e --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/AmazonDynamoDB.java @@ -0,0 +1,14 @@ +package guice.relearn_2019_09._9_inject_the_same_object_in_two_modules; + +public class AmazonDynamoDB { + /** + * This is a dummy class since AWS DynamoDB Maven depdency cannot be resolved in my local. + */ + private final String awsRegion; + private final String ddbEndPoint; + + public AmazonDynamoDB(String awsRegion, String ddbEndPoint) { + this.awsRegion = awsRegion; + this.ddbEndPoint = ddbEndPoint; + } +} diff --git a/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/ClassA.java b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/ClassA.java new file mode 100644 index 0000000..54cb795 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/ClassA.java @@ -0,0 +1,10 @@ +package guice.relearn_2019_09._9_inject_the_same_object_in_two_modules; + +import com.google.inject.Inject; +import lombok.AllArgsConstructor; + +@AllArgsConstructor(onConstructor = @__(@Inject)) +public class ClassA { + private final CustomerDbDao customerDbDao; + private static final String message = "This is from ClassA!"; +} diff --git a/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/ClassB.java b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/ClassB.java new file mode 100644 index 0000000..4e28135 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/ClassB.java @@ -0,0 +1,10 @@ +package guice.relearn_2019_09._9_inject_the_same_object_in_two_modules; + +import com.google.inject.Inject; +import lombok.AllArgsConstructor; + +@AllArgsConstructor(onConstructor = @__(@Inject)) +public class ClassB { + private final CustomerDbDao customerDbDao; + private static final String message = "This is from ClassB!"; +} diff --git a/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/CustomerDbDao.java b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/CustomerDbDao.java new file mode 100644 index 0000000..311cca0 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/CustomerDbDao.java @@ -0,0 +1,19 @@ +package guice.relearn_2019_09._9_inject_the_same_object_in_two_modules; + +import com.google.inject.Inject; +import com.google.inject.name.Named; + +public class CustomerDbDao { + public static final String CUSTOMER_DDB = "Customer.DDB"; + + private final DynamoDBMapper dynamoDBMapper; + + @Inject + public CustomerDbDao(@Named(CUSTOMER_DDB) DynamoDBMapper dynamoDBMapper) { + this.dynamoDBMapper = dynamoDBMapper; + } + + public void work() { + System.out.println("CustomerDbDao object is talking to Amazon DynamoDB and doing its work!"); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/DynamoDBMapper.java b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/DynamoDBMapper.java new file mode 100644 index 0000000..9deb89d --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/DynamoDBMapper.java @@ -0,0 +1,13 @@ +package guice.relearn_2019_09._9_inject_the_same_object_in_two_modules; + +public class DynamoDBMapper { + /** + * This is a dummy class since AWS DynamoDB Maven depdency cannot be resolved in my local. + */ + + private final AmazonDynamoDB dynamodb; + + public DynamoDBMapper(AmazonDynamoDB dynamodb) { + this.dynamodb = dynamodb; + } +} diff --git a/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/MainApp.java b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/MainApp.java new file mode 100644 index 0000000..5e87ba5 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/MainApp.java @@ -0,0 +1,20 @@ +package guice.relearn_2019_09._9_inject_the_same_object_in_two_modules; + +import com.google.inject.Guice; +import com.google.inject.Injector; + +public class MainApp { + + public static void main(String... args) { + try { + Injector injector = Guice.createInjector(new WorkersModule()); + System.out.println("created injector: " + injector); + WorkersRunner workersRunner = injector.getInstance(WorkersRunner.class); + System.out.println("got workersRunner: " + workersRunner); + workersRunner.start(); + workersRunner.shutdown(); + } catch (Exception e) { + System.out.println("caught exception, e: " + e); + } + } +} diff --git a/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/Worker.java b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/Worker.java new file mode 100644 index 0000000..72eefb7 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/Worker.java @@ -0,0 +1,7 @@ +package guice.relearn_2019_09._9_inject_the_same_object_in_two_modules; + +public interface Worker { + void start(); + + void shutdown(); +} diff --git a/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/Worker1.java b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/Worker1.java new file mode 100644 index 0000000..cc44d66 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/Worker1.java @@ -0,0 +1,26 @@ +package guice.relearn_2019_09._9_inject_the_same_object_in_two_modules; + +import com.google.inject.Inject; +import com.google.inject.name.Named; + +import static guice.relearn_2019_09._9_inject_the_same_object_in_two_modules.Worker1Module.WORKER1; + +public class Worker1 implements Worker { + private final CustomerDbDao customerDbDao; + + @Inject + public Worker1(@Named(WORKER1) CustomerDbDao customerDbDao) { + this.customerDbDao = customerDbDao; + } + + @Override + public void start() { + System.out.println("Worker1 started working!"); + } + + @Override + public void shutdown() { + System.out.println("Worker1 has shut down!"); + } + +} diff --git a/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/Worker1Module.java b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/Worker1Module.java new file mode 100644 index 0000000..d2ef13e --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/Worker1Module.java @@ -0,0 +1,47 @@ +package guice.relearn_2019_09._9_inject_the_same_object_in_two_modules; + +import com.google.inject.PrivateModule; +import com.google.inject.Provides; +import com.google.inject.Singleton; +import com.google.inject.multibindings.Multibinder; +import com.google.inject.name.Named; +import com.google.inject.name.Names; + +import static guice.relearn_2019_09._9_inject_the_same_object_in_two_modules.CustomerDbDao.CUSTOMER_DDB; + +public class Worker1Module extends PrivateModule { + + public static final String WORKER1 = "Worker1"; + private static final String DDB_END_POINT = "dynamodb.us-west-2.amazonaws.com"; + private static final String AWS_REGION = "us-west-2"; + + @Override + protected void configure() { + final Multibinder multibinder = Multibinder.newSetBinder(binder(), Worker.class); + multibinder.addBinding().to(Worker1.class); + + bind(String.class).annotatedWith(Names.named(AWS_REGION)).toInstance("cool"); + bind(String.class).annotatedWith(Names.named(DDB_END_POINT)).toInstance("cool1"); + } + + @Provides + @Singleton + @Named(WORKER1) + public CustomerDbDao providesCustomerDbDao(@Named(CUSTOMER_DDB) DynamoDBMapper dynamoDBMapper) { + return new CustomerDbDao(dynamoDBMapper); + } + + @Provides + @Singleton + @Named(CUSTOMER_DDB) + public DynamoDBMapper provideDynamoDBMapper(@Named(CUSTOMER_DDB) AmazonDynamoDB dynamodb) { + return new DynamoDBMapper(dynamodb); + } + + @Provides + @Singleton + @Named(CUSTOMER_DDB) + public AmazonDynamoDB provideDynamoDBClient(final @Named(AWS_REGION) String awsRegion, final @Named(DDB_END_POINT) String ddbEndPoint) { + return new AmazonDynamoDB(awsRegion, ddbEndPoint); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/Worker2.java b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/Worker2.java new file mode 100644 index 0000000..78ef7bf --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/Worker2.java @@ -0,0 +1,23 @@ +package guice.relearn_2019_09._9_inject_the_same_object_in_two_modules; + +import com.google.inject.Inject; +import com.google.inject.name.Named; + +public class Worker2 implements Worker { + private final CustomerDbDao customerDbDao; + + @Inject + public Worker2(@Named("Worker2") CustomerDbDao customerDbDao) { + this.customerDbDao = customerDbDao; + } + + @Override + public void start() { + System.out.println("Worker2 started working!"); + } + + @Override + public void shutdown() { + System.out.println("Worker2 has shut down!"); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/Worker2Module.java b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/Worker2Module.java new file mode 100644 index 0000000..473a041 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/Worker2Module.java @@ -0,0 +1,46 @@ +package guice.relearn_2019_09._9_inject_the_same_object_in_two_modules; + +import com.google.inject.PrivateModule; +import com.google.inject.Provides; +import com.google.inject.Singleton; +import com.google.inject.multibindings.Multibinder; +import com.google.inject.name.Named; +import com.google.inject.name.Names; + +import static guice.relearn_2019_09._9_inject_the_same_object_in_two_modules.CustomerDbDao.CUSTOMER_DDB; + +public class Worker2Module extends PrivateModule { + + public static final String WORKER2 = "Worker2"; + private static final String DDB_END_POINT = "dynamodb.us-west-2.amazonaws.com"; + private static final String AWS_REGION = "us-west-2"; + + @Override + protected void configure() { +// final Multibinder multibinder = Multibinder.newSetBinder(binder(), Worker.class); +// multibinder.addBinding().to(Worker2.class); +// bind(String.class).annotatedWith(Names.named(AWS_REGION)).toInstance("cool"); +// bind(String.class).annotatedWith(Names.named(DDB_END_POINT)).toInstance("cool1"); + } + + @Provides + @Singleton + @Named(WORKER2) + public CustomerDbDao providesCustomerDbDao(@Named(CUSTOMER_DDB) DynamoDBMapper dynamoDBMapper) { + return new CustomerDbDao(dynamoDBMapper); + } + + @Provides + @Singleton + @Named(CUSTOMER_DDB) + public DynamoDBMapper provideDynamoDBMapper(@Named(CUSTOMER_DDB) AmazonDynamoDB dynamodb) { + return new DynamoDBMapper(dynamodb); + } + + @Provides + @Singleton + @Named(CUSTOMER_DDB) + public AmazonDynamoDB provideDynamoDBClient(final @Named(AWS_REGION) String awsRegion, final @Named(DDB_END_POINT) String ddbEndPoint) { + return new AmazonDynamoDB(awsRegion, ddbEndPoint); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/WorkersModule.java b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/WorkersModule.java new file mode 100644 index 0000000..e3213b0 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/WorkersModule.java @@ -0,0 +1,12 @@ +package guice.relearn_2019_09._9_inject_the_same_object_in_two_modules; + +import com.google.inject.AbstractModule; + +public class WorkersModule extends AbstractModule { + + @Override + protected void configure() { + install(new Worker1Module()); +// install(new Worker2Module()); + } +} diff --git a/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/WorkersRunner.java b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/WorkersRunner.java new file mode 100644 index 0000000..898ed33 --- /dev/null +++ b/src/main/java/guice/relearn_2019_09/_9_inject_the_same_object_in_two_modules/WorkersRunner.java @@ -0,0 +1,38 @@ +package guice.relearn_2019_09._9_inject_the_same_object_in_two_modules; + +import lombok.extern.slf4j.Slf4j; +import lombok.val; + +import javax.inject.Inject; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +public class WorkersRunner { + + @Inject + private Set workers; + + public void start() { + log.info("Starting up Background Workers: " + workers.stream() + .map((w) -> w.getClass().getSimpleName()) + .collect(Collectors.joining(","))); + + val now = System.currentTimeMillis(); + + workers.forEach((w) -> { + log.info("Starting up " + w.getClass().getName() + "..."); + w.start(); + log.info("Start up took " + (System.currentTimeMillis() - now) + " ms"); + }); + } + + /** + * Shutdown workers gracefully + */ + public void shutdown() { + workers.forEach((w) -> { + w.shutdown(); + }); + } +} diff --git a/src/interviewQuestions/BinarySearch.java b/src/main/java/interviewQuestions/BinarySearch.java similarity index 100% rename from src/interviewQuestions/BinarySearch.java rename to src/main/java/interviewQuestions/BinarySearch.java diff --git a/src/interviewQuestions/BuildOrder.java b/src/main/java/interviewQuestions/BuildOrder.java similarity index 100% rename from src/interviewQuestions/BuildOrder.java rename to src/main/java/interviewQuestions/BuildOrder.java diff --git a/src/main/java/interviewQuestions/CirclePairing.java b/src/main/java/interviewQuestions/CirclePairing.java new file mode 100644 index 0000000..b0b8bb9 --- /dev/null +++ b/src/main/java/interviewQuestions/CirclePairing.java @@ -0,0 +1,183 @@ +package interviewQuestions; + +public class CirclePairing { + + /**Round 1: give two words, find the longest common prefix between the two. + * This should be super easy. Just to warm up the candidate. + * + * Round 2: what if you're given N words + * + * ["flower","flow","flight"] return "fl" + * ["dog","racecar","car"] return "" + * + * what's the time complexity of your solution? O(S) where S is all the chars in all strings, since in the worst case, all the strings are the same + * what's the space complexity of your solution? O(1) no additional space needed. + * */ + + /**Solution 1: Horizontal scanning*/ + public String longestCommonPrefix_horizontalScanning(String[] strs) { + if (strs.length == 0) { + return ""; + } + String prefix = strs[0]; + for (int i = 1; i < strs.length; i++) { + while (strs[i].indexOf(prefix) != 0) { + prefix = prefix.substring(0, prefix.length() - 1); + if (prefix.isEmpty()) { + return ""; + } + } + } + return prefix; + } + + /**Solution 2: vertical scanning*/ + public String longestCommonPrefix_verticalScanning(String[] strs) { + if (strs == null || strs.length == 0) { + return ""; + } + for (int i = 0; i < strs[0].length() ; i++){ + char c = strs[0].charAt(i); + for (int j = 1; j < strs.length; j ++) { + if (i == strs[j].length() || strs[j].charAt(i) != c) + return strs[0].substring(0, i); + } + } + return strs[0]; + } + + /**Solution 2: vertical scanning, verbose version*/ + public String longestCommonPrefix_verticalScanningVerbose(String[] strs) { + if (strs == null || strs.length == 0) { + return ""; + } + String shortestWord = strs[0]; + for (String word : strs) { + if (shortestWord.length() > word.length()) { + shortestWord = word; + } + } + for (int i = 0; i < shortestWord.length(); i++) { + for (int j = 0; j < strs.length; j++) { + if (strs[j].charAt(i) != shortestWord.charAt(i)) { + return i == 0 ? "" : shortestWord.substring(0, i); + } + } + } + return shortestWord; + } + + /** + * Round 3: + * + * Suppose the given list of words are highly sorted and there're over 10 billion words. + * Design an algorithm that works efficiently. + * + * e.g. input: + * abandon + * ability + * able + * about + * above + * abroad + * absence + * absent + * absolute + * abusive + * academic + * ... + * zoo + * zyzzyva + * + * Trie should be the answer. + * + * what's the time complexity of your solution? + * what's the space complexity of your solution? + * */ + + public static class Solution1 { + class TrieNode { + + char val; + boolean isWord; + TrieNode[] children = new TrieNode[26]; + + // Initialize your data structure here. + public TrieNode() { + } + + public TrieNode(char c) { + this.val = c; + } + } + + public class Trie { + private TrieNode root; + + public Trie() { + root = new TrieNode(); + root.val = ' ';//initialize root to be an empty char, this is a common practice as how Wiki defines Trie data structure as well + } + + // Inserts a word into the trie. + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + if (node.children[word.charAt(i) - 'a'] == null) { + node.children[word.charAt(i) - 'a'] = new TrieNode(word.charAt(i)); + } + node = node.children[word.charAt(i) - 'a']; + } + node.isWord = true; + } + + // Returns if the word is in the trie. + public boolean search(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + if (node.children[word.charAt(i) - 'a'] == null) { + return false; + } + node = node.children[word.charAt(i) - 'a']; + } + return node.isWord; + } + + // Returns if there is any word in the trie + // that starts with the given prefix. + public boolean startsWith(String prefix) { + TrieNode node = root; + for (int i = 0; i < prefix.length(); i++) { + if (node.children[prefix.charAt(i) - 'a'] == null) { + return false; + } + node = node.children[prefix.charAt(i) - 'a']; + } + return true; + } + } + + // Your Trie object will be instantiated and called as such: + // Trie trie = new Trie(); + // trie.insert("somestring"); + // trie.search("key"); + } + + /** + * Round 4: + * + * What if the given list needs to support more than English characters? For instance, we have international markets like Japan, + * how do we support Japanase characters?*/ + + + /** Round 5: How to support constantly adding new words and removing existing words, also return longest common prefix at any given timestamp*/ + + + public static void main(String... args) { + CirclePairing circlePairing = new CirclePairing(); + System.out.println("Hello world!"); + //String[] strs = new String[]{"flower","flow","flight"}; + String[] strs = new String[]{"dog","racecar","car"}; + System.out.println(circlePairing.longestCommonPrefix_verticalScanningVerbose(strs)); + } +} diff --git a/src/interviewQuestions/ColorCombinations.java b/src/main/java/interviewQuestions/ColorCombinations.java similarity index 100% rename from src/interviewQuestions/ColorCombinations.java rename to src/main/java/interviewQuestions/ColorCombinations.java diff --git a/src/interviewQuestions/ConcatenatedWords.java b/src/main/java/interviewQuestions/ConcatenatedWords.java similarity index 100% rename from src/interviewQuestions/ConcatenatedWords.java rename to src/main/java/interviewQuestions/ConcatenatedWords.java diff --git a/src/interviewQuestions/ConcatenatedWordsII.java b/src/main/java/interviewQuestions/ConcatenatedWordsII.java similarity index 100% rename from src/interviewQuestions/ConcatenatedWordsII.java rename to src/main/java/interviewQuestions/ConcatenatedWordsII.java diff --git a/src/interviewQuestions/FindLongestSuffixInTwoLists.java b/src/main/java/interviewQuestions/FindLongestSuffixInTwoLists.java similarity index 100% rename from src/interviewQuestions/FindLongestSuffixInTwoLists.java rename to src/main/java/interviewQuestions/FindLongestSuffixInTwoLists.java diff --git a/src/main/java/interviewQuestions/FindWordFromNumber.java b/src/main/java/interviewQuestions/FindWordFromNumber.java new file mode 100644 index 0000000..297c907 --- /dev/null +++ b/src/main/java/interviewQuestions/FindWordFromNumber.java @@ -0,0 +1,302 @@ +package interviewQuestions; + +/**With Cracking group on 11/23/2013, a very fruitful day. + + * + *Problem statement (Dropbox interview question): + *Given a defined dictionary, test if a 7-digit number can represent any + *valid words from this dictionary. + *The digit to alphabet matching relationship is exactly the same as from the cellphone keyboard. + */ + +/**The idea here is that: + *This 7-digit number can only be separated into the following three situations: + *a 3-letter word followed by a 4-letter word; + *a 4-letter word followed by a 3-letter word; + *a 7-letter word. + *Because we assume there's no word with only one letter or two letters in our dictionary.*/ + + + +/**Then we construct another three HashMaps to store all 3-letter words, all 4-letter words and + * all 7-letter words in the dictionary respectively. */ +import java.util.ArrayList; +import java.util.HashMap; + +public class FindWordFromNumber { + +/**The KEY thing to bare in mind is that in HashMap, + *you can only get values using key, NOT the other way around!*/ + + public static void main(String args[]){ + + /**We construct our first HashMap, ATTENTION: in this HashMap, the key is the alphabet + *while the value is its corresponding digit, because we want to find the digit from + *the alphabet.*/ + HashMap charToNum = new HashMap(); + charToNum.put('a', 2); + charToNum.put('b', 2); + charToNum.put('c', 2); + charToNum.put('d', 3); + charToNum.put('e', 3); + charToNum.put('f', 3); + charToNum.put('g', 4); + charToNum.put('h', 4); + charToNum.put('i', 4); + charToNum.put('j', 5); + charToNum.put('k', 5); + charToNum.put('l', 5); + charToNum.put('m', 6); + charToNum.put('n', 6); + charToNum.put('o', 6); + charToNum.put('p', 7); + charToNum.put('q', 7); + charToNum.put('r', 7); + charToNum.put('s', 7); + charToNum.put('t', 8); + charToNum.put('u', 8); + charToNum.put('v', 8); + charToNum.put('w', 9); + charToNum.put('x', 9); + charToNum.put('y', 9); + charToNum.put('z', 9); + + /**I should use the above HashMap to automatically put the words in the dictionary into + *their corresponding HashMaps and, inside their corresponding HashMaps to their corresponding + *key.*/ + + /**So I commented the following manual assigning methods out.*/ + + /**HashMap threeLetterWord = new HashMap(); + threeLetterWord.put(567, "lop"); + threeLetterWord.put(432, "ifc"); + threeLetterWord.put(527, "lap"); + threeLetterWord.put(827, "tap"); + threeLetterWord.put(567, "lmp"); + threeLetterWord.put(438, "get"); + + HashMap fourLetterWord = new HashMap(); + fourLetterWord.put(5678, "jmpu"); + fourLetterWord.put(8432, "thea"); + fourLetterWord.put(7843, "ruif"); + fourLetterWord.put(8432, "vida"); + + HashMap sevenLetterWord = new HashMap(); + sevenLetterWord.put(5678432, "kostiea"); + sevenLetterWord.put(5678432, "kmpugec"); + */ + +// Declare an array of type String to hold the whole dictionary. + String dict[] = {"lop", "ifc", "lap", "tap", "lmp", "get", + "jmpu", "thea", "ruif", "vida", "kostiea", "kmpugec"}; + + + /**Attention: the parameters inside the HashMap: one is Integer which represents digit, + * the other is ArrayList which is used to store all possible valid words that this + * number can represent. Because one number can represent a couple different words.*/ + HashMap> threeLetterWord = new HashMap(); + HashMap> fourLetterWord = new HashMap(); + HashMap> sevenLetterWord = new HashMap(); + + for(int i = 0; i < dict.length; i++) + { + if(dict[i].length() == 3){ + String num = ""; + for(int j = 0; j < dict[i].length(); j++){ + String temp = String.valueOf(charToNum.get(dict[i].charAt(j))); + num = num + temp; + } + int _3LetterWordNum = Integer.parseInt(num); + /**Here we need to test if this number has already had one valid word + *put in the HashMap, + * + *if so, we need to get whole ArrayList elements out + *first, then use ArrayList.add() method to append this word at the end of + *the last word that this number represents, then put it in the HashMap; + * + *if not, this means this word is the first word that this number + *represents in the dictionary, so we just put + *it in the ArrayList, then put it in the HashMap. */ + if(threeLetterWord.containsKey(_3LetterWordNum)) + { ArrayList allString = new ArrayList(); + allString = threeLetterWord.get(_3LetterWordNum); + allString.add(dict[i]); + threeLetterWord.put(_3LetterWordNum, allString); + } + else{ + ArrayList allString = new ArrayList(); + allString.add(dict[i]); + threeLetterWord.put(_3LetterWordNum, allString); + } + } + else if (dict[i].length() == 4){ + String num = ""; + for(int j = 0; j < dict[i].length(); j++){ + String temp = String.valueOf(charToNum.get(dict[i].charAt(j))); + num = num + temp; + } + int _4LetterWordNum = Integer.parseInt(num); + if(fourLetterWord.containsKey(_4LetterWordNum)) + { + ArrayList allString = new ArrayList(); + allString = fourLetterWord.get(_4LetterWordNum); + allString.add(dict[i]); + fourLetterWord.put(_4LetterWordNum, allString); + } + else{ + ArrayList allString = new ArrayList(); + allString.add(dict[i]); + fourLetterWord.put(_4LetterWordNum, allString); + } + } + else if (dict[i].length() == 7){ + String num = ""; + for(int j = 0; j < dict[i].length(); j++){ + String temp = String.valueOf(charToNum.get(dict[i].charAt(j))); + num = num + temp; + } + int _7LetterWordNum = Integer.parseInt(num); + if(sevenLetterWord.containsKey(_7LetterWordNum)) + { ArrayList allString = new ArrayList(); + allString = sevenLetterWord.get(_7LetterWordNum); + allString.add(dict[i]); + sevenLetterWord.put(_7LetterWordNum, allString); + } + else{ + ArrayList allString = new ArrayList(); + allString.add(dict[i]); + sevenLetterWord.put(_7LetterWordNum, allString); + } + } + } + + /**Use HashMap.values() method to get all the VALUES inside this HashMap.*/ +// System.out.println(threeLetterWord.values()); +// System.out.println(fourLetterWord.values()); +// System.out.println(sevenLetterWord.values()); + + /*Use HashMap.keySet() method to get all the KEYS inside this HashMap.*/ +// System.out.println(threeLetterWord.keySet()); +// System.out.println(fourLetterWord.keySet()); +// System.out.println(sevenLetterWord.keySet()); + + String input = "1020"; + + if(input.length() <= 2){ + System.out.println("Your number has less than 3 digits," + + " cannot be used to represent any valid words" + + " in our dictionary, please enter a seven-digit number"); + } + + else if(input.length() == 3)/*When the input string has 3 digits.*/ + { + if(threeLetterWord.containsKey(Integer.parseInt(input))) + { + ArrayList temp3word = new ArrayList(); + temp3word = threeLetterWord.get(Integer.parseInt(input)); + for(String i : temp3word) + System.out.println(i); + } + else + System.out.print("No valid word combinations for this 3-digit number" + + ", please enter another number."); + } + + else if(input.length() == 4)/*When the input string has 4 digits.*/ + { + if(fourLetterWord.containsKey(Integer.parseInt(input))) + { + ArrayList temp4word = new ArrayList(); + temp4word = fourLetterWord.get(Integer.parseInt(input)); + for(String i : temp4word) + System.out.println(i); + } + else + System.out.println("No valid word combinations for this 4-digit number" + + ", please enter another number."); + } + else if(input.length() == 5) + System.out.println("No valid word combinations for a 5-digit number," + + " please enter another number."); + else if(input.length() == 6) + System.out.println("No valid word combinations for a 6-digit number," + + " please enter another number."); + + else if(input.length() == 7)/**When the input string has 7 digits, there are three possible + situations for this, as follows:*/ + { + if(sevenLetterWord.containsKey(Integer.parseInt(input))) + //the following is the situation that there's only seven-letter word + { ArrayList temp7word = new ArrayList(); + temp7word = sevenLetterWord.get(Integer.parseInt(input)); + System.out.println("This 7-digit number as a whole macthes valid words in the dictonary," + + " they are: "); + for(String i : temp7word) + { + System.out.println(i); + } + } + + if(threeLetterWord.containsKey(Integer.parseInt(input.substring(0, 3)))){ + { + //the following is the situation that there's three-letter word followed by a four-letter word + ArrayList temp3word = new ArrayList(); + ArrayList temp4word = new ArrayList(); + String s1 = input.substring(0, 3);/*Pay ATTENTION to the substring method: + it can take char at index 0 but cannot take char at index 3, so in order to get + the first three chars of the String, we need to use .substring(0, 3) instead of + .substring(0, 2).*/ + //System.out.println(s1); + String s2 = input.substring(3, 7); + //System.out.println(s2); + if(fourLetterWord.containsKey(Integer.parseInt(s2))) + { System.out.println("This number can represent one 3-letter word followed by" + + " a 4-letter word, they are:"); + temp3word = threeLetterWord.get(Integer.parseInt(s1)); + temp4word = fourLetterWord.get(Integer.parseInt(s2)); + for(String i : temp3word) + for(String j : temp4word){ + System.out.println(i + " + " + j); + } + } + else + System.out.println("There's valid word for the first 3 digits but no valid words" + + " for the last 4-digit number."); + } + } + + //the following is the situation that there's four-letter word followed by a three-letter word + if(fourLetterWord.containsKey(Integer.parseInt(input.substring(0, 4)))) + { + { + String s1 = input.substring(0, 4); + //System.out.println(s1); + ArrayList temp4word = new ArrayList(); + ArrayList temp3word = new ArrayList(); + + String s2 = input.substring(4, 7); + //System.out.println(s2); + if(threeLetterWord.containsKey(Integer.parseInt(s2))) + { System.out.println("This number can represent one 4-letter word followed by" + + " a 3-letter word, they are:"); + temp4word = fourLetterWord.get(Integer.parseInt(s1)); + temp3word = threeLetterWord.get(Integer.parseInt(s2)); + for(String i : temp4word) + for(String j : temp3word){ + System.out.print(i + " + " + j); + } + } + else + System.out.println("There is valid word combinations for the first 4-digit of" + + "this number, but there's no valid word for the last 3-digit."); + } + } + + else + System.out.println("This 7-digit number doesn't not match any 3-letter word, 4-letter word or" + + " 7-letter word in the dictionary."); + } + else + System.out.println("Too long input, please enter a valid number."); + } +} diff --git a/src/interviewQuestions/LongestConsecutivePathInAMatrix.java b/src/main/java/interviewQuestions/LongestConsecutivePathInAMatrix.java similarity index 100% rename from src/interviewQuestions/LongestConsecutivePathInAMatrix.java rename to src/main/java/interviewQuestions/LongestConsecutivePathInAMatrix.java diff --git a/src/interviewQuestions/MaximumSizeSubarraySumEqualsOrSmallerThanK.java b/src/main/java/interviewQuestions/MaximumSizeSubarraySumEqualsOrSmallerThanK.java similarity index 100% rename from src/interviewQuestions/MaximumSizeSubarraySumEqualsOrSmallerThanK.java rename to src/main/java/interviewQuestions/MaximumSizeSubarraySumEqualsOrSmallerThanK.java diff --git a/src/interviewQuestions/MinFloors.java b/src/main/java/interviewQuestions/MinFloors.java similarity index 100% rename from src/interviewQuestions/MinFloors.java rename to src/main/java/interviewQuestions/MinFloors.java diff --git a/src/interviewQuestions/SetValueInDependencyGraph.java b/src/main/java/interviewQuestions/SetValueInDependencyGraph.java similarity index 100% rename from src/interviewQuestions/SetValueInDependencyGraph.java rename to src/main/java/interviewQuestions/SetValueInDependencyGraph.java diff --git a/src/main/java/interviewQuestions/distributeProceeds/Associate.java b/src/main/java/interviewQuestions/distributeProceeds/Associate.java new file mode 100644 index 0000000..5cade65 --- /dev/null +++ b/src/main/java/interviewQuestions/distributeProceeds/Associate.java @@ -0,0 +1,9 @@ +package interviewQuestions.distributeProceeds; + +public class Associate extends Role { + public static final String ASSOCIATE = "ASSOCIATE"; + + public Associate() { + this.name = ASSOCIATE; + } +} diff --git a/src/main/java/interviewQuestions/distributeProceeds/DistributeProceedsService.java b/src/main/java/interviewQuestions/distributeProceeds/DistributeProceedsService.java new file mode 100644 index 0000000..c496abb --- /dev/null +++ b/src/main/java/interviewQuestions/distributeProceeds/DistributeProceedsService.java @@ -0,0 +1,5 @@ +package interviewQuestions.distributeProceeds; + +public interface DistributeProceedsService { + DistributionResponse distributeProceeds(Double proceed); +} diff --git a/src/main/java/interviewQuestions/distributeProceeds/DistributeProceedsServiceImpl.java b/src/main/java/interviewQuestions/distributeProceeds/DistributeProceedsServiceImpl.java new file mode 100644 index 0000000..6952a9b --- /dev/null +++ b/src/main/java/interviewQuestions/distributeProceeds/DistributeProceedsServiceImpl.java @@ -0,0 +1,92 @@ +package interviewQuestions.distributeProceeds; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class DistributeProceedsServiceImpl implements DistributeProceedsService { + + private static final String ASSOCIATE = "ASSOCIATE"; + private static final String GENERAL_PARTNER = "GENERAL_PARTNER"; + private static final String MANAGING_PARTNER = "MANAGING_PARTNER"; + + private final List shareholders; + + public DistributeProceedsServiceImpl(List shareholders) { + this.shareholders = shareholders; + } + + public DistributionResponse distributeProceeds(Double proceed) { + Double totalClassBFunds = 0.0; + int totalClassBUnits = 0; + int totalUnits = 0; + for (Person person : shareholders) { + Map assumedRolesToShareCount = person.getAssumedRolesToShareCount(); + for (Role role : assumedRolesToShareCount.keySet()) { + if (role.name.equals(GENERAL_PARTNER)) { + totalClassBFunds += ((GeneralPartner) role).initInvestment; + totalClassBUnits += assumedRolesToShareCount.get(role); + } + totalUnits += assumedRolesToShareCount.get(role); + } + } + Double remaining = 0.0; + Double totalClassBProceeds; + if (proceed > totalClassBFunds) { + remaining = proceed - totalClassBFunds; + totalClassBProceeds = totalClassBFunds; + } else { + totalClassBProceeds = proceed; + } + //distribute to ClassB holders first + for (Person person : shareholders) { + Map assumedRolesToShareCount = person.getAssumedRolesToShareCount(); + for (Role role : assumedRolesToShareCount.keySet()) { + if (role.getName().equals(GENERAL_PARTNER)) { + Double percentage = assumedRolesToShareCount.get(role) * 1.0 / totalClassBUnits; + double classBProceed = percentage * totalClassBProceeds; + Map assumedRolesAndProceeds = person.getAssumedRolesAndProceeds(); + assumedRolesAndProceeds.put(role, classBProceed); + person.setAssumedRolesAndProceeds(assumedRolesAndProceeds); + break; + } + } + } + Double totalClassAProceeds = 0.0; + Double totalClassCProceeds = 0.0; + if (remaining > 0) { + //distribute among all classes if there's any remaining + for (Person person : shareholders) { + Map assumedRolesToShareCount = person.getAssumedRolesToShareCount(); + for (Role role : assumedRolesToShareCount.keySet()) { + Double percentage = assumedRolesToShareCount.get(role) * 1.0 / totalUnits; + Double classProceeds = 0.0; + if (role.getName().equals(ASSOCIATE)) { + classProceeds = percentage * remaining; + totalClassAProceeds += classProceeds; + } else if (role.getName().equals(MANAGING_PARTNER)) { + classProceeds = percentage * remaining; + totalClassCProceeds += classProceeds; + } else if (role.getName().equals(GENERAL_PARTNER)) { + classProceeds = percentage * remaining; + totalClassBProceeds += classProceeds; + } + Map assumedRolesAndProceeds = person.getAssumedRolesAndProceeds(); + assumedRolesAndProceeds.put(role, assumedRolesAndProceeds.getOrDefault(role, 0.0) + classProceeds); + person.setAssumedRolesAndProceeds(assumedRolesAndProceeds); + } + } + } + + List payOutAndShareClassList = Arrays.asList( + new PayOutAndShareClass(Math.round(totalClassAProceeds * 100) / 100.0, "Class A"), + new PayOutAndShareClass(Math.round(totalClassBProceeds * 100) / 100.0, "Class B"), + new PayOutAndShareClass(Math.round(totalClassCProceeds * 100) / 100.0, "Class C")); + List payoutAndPersonList = shareholders.stream().map(person -> new PayoutAndPerson(person.getName(), person.getTotalPayout())).collect(Collectors.toList()); + DistributionResponse distributionResponse = new DistributionResponse( + new PayoutByPerson(payoutAndPersonList), new PayoutByShareclass(payOutAndShareClassList)); + return distributionResponse; + } + +} diff --git a/src/main/java/interviewQuestions/distributeProceeds/DistributionResponse.java b/src/main/java/interviewQuestions/distributeProceeds/DistributionResponse.java new file mode 100644 index 0000000..750eeee --- /dev/null +++ b/src/main/java/interviewQuestions/distributeProceeds/DistributionResponse.java @@ -0,0 +1,11 @@ +package interviewQuestions.distributeProceeds; + +public class DistributionResponse { + public DistributionResponse(PayoutByPerson payoutByPerson, PayoutByShareclass payoutByShareclass) { + this.payoutByPerson = payoutByPerson; + this.payoutByShareclass = payoutByShareclass; + } + + PayoutByPerson payoutByPerson; + PayoutByShareclass payoutByShareclass; +} diff --git a/src/main/java/interviewQuestions/distributeProceeds/EntryClass.java b/src/main/java/interviewQuestions/distributeProceeds/EntryClass.java new file mode 100644 index 0000000..e82ba5b --- /dev/null +++ b/src/main/java/interviewQuestions/distributeProceeds/EntryClass.java @@ -0,0 +1,44 @@ +package interviewQuestions.distributeProceeds; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public class EntryClass { + + public static void main(String... args) { + EntryClass entryClass = new EntryClass(); + List shareholders = entryClass.initShareholders(); + DistributeProceedsService distributeProceedsService = new DistributeProceedsServiceImpl(shareholders); + if (args.length > 0) { + System.out.println(args[0]); + System.out.println(distributeProceedsService.distributeProceeds(Double.parseDouble(args[0]))); + } + DistributionResponse response = distributeProceedsService.distributeProceeds(1000.0); + List payoutAndPersonList = response.payoutByPerson.payoutAndPersonList; + System.out.println(payoutAndPersonList.toString()); + List payOutAndShareClassList = response.payoutByShareclass.payOutAndShareClassList; + System.out.println(payOutAndShareClassList.toString()); + System.out.println("Finished running the program."); + } + + private List initShareholders() { + Person alex = new Person("Alex"); + Map alexRoles = alex.getAssumedRolesToShareCount(); + alexRoles.put(new GeneralPartner(250l), 10); + alex.setAssumedRoles(alexRoles); + + Person becky = new Person("Becky"); + Map beckyRoles = becky.getAssumedRolesToShareCount(); + beckyRoles.put(new GeneralPartner(250l), 10); + beckyRoles.put(new ManagingPartner(), 5); + becky.setAssumedRoles(beckyRoles); + + Person david = new Person("David"); + Map davidRoles = david.getAssumedRolesToShareCount(); + davidRoles.put(new Associate(), 10); + david.setAssumedRoles(davidRoles); + + return Arrays.asList(alex, becky, david); + } +} diff --git a/src/main/java/interviewQuestions/distributeProceeds/GeneralPartner.java b/src/main/java/interviewQuestions/distributeProceeds/GeneralPartner.java new file mode 100644 index 0000000..81348f8 --- /dev/null +++ b/src/main/java/interviewQuestions/distributeProceeds/GeneralPartner.java @@ -0,0 +1,12 @@ +package interviewQuestions.distributeProceeds; + +public class GeneralPartner extends Role { + public static final String GENERAL_PARTNER = "GENERAL_PARTNER"; + + public GeneralPartner(Long initInvestment) { + this.initInvestment = initInvestment; + this.name = GENERAL_PARTNER; + } + + Long initInvestment; +} diff --git a/src/main/java/interviewQuestions/distributeProceeds/ManagingPartner.java b/src/main/java/interviewQuestions/distributeProceeds/ManagingPartner.java new file mode 100644 index 0000000..7a47abe --- /dev/null +++ b/src/main/java/interviewQuestions/distributeProceeds/ManagingPartner.java @@ -0,0 +1,9 @@ +package interviewQuestions.distributeProceeds; + +public class ManagingPartner extends Role { + public static final String MANAGING_PARTNER = "MANAGING_PARTNER"; + + public ManagingPartner() { + this.name = MANAGING_PARTNER; + } +} diff --git a/src/main/java/interviewQuestions/distributeProceeds/PayOutAndShareClass.java b/src/main/java/interviewQuestions/distributeProceeds/PayOutAndShareClass.java new file mode 100644 index 0000000..e56d7a3 --- /dev/null +++ b/src/main/java/interviewQuestions/distributeProceeds/PayOutAndShareClass.java @@ -0,0 +1,19 @@ +package interviewQuestions.distributeProceeds; + +public class PayOutAndShareClass { + Double payoutAmount; + String shareClass; + + public PayOutAndShareClass(Double payoutAmount, String shareClass) { + this.payoutAmount = payoutAmount; + this.shareClass = shareClass; + } + + @Override + public String toString() { + return "PayOutAndShareClass{" + + "payoutAmount=" + payoutAmount + + ", shareClass='" + shareClass + '\'' + + '}'; + } +} diff --git a/src/main/java/interviewQuestions/distributeProceeds/PayoutAndPerson.java b/src/main/java/interviewQuestions/distributeProceeds/PayoutAndPerson.java new file mode 100644 index 0000000..b0ae0b2 --- /dev/null +++ b/src/main/java/interviewQuestions/distributeProceeds/PayoutAndPerson.java @@ -0,0 +1,19 @@ +package interviewQuestions.distributeProceeds; + +public class PayoutAndPerson { + String name; + Double payoutAmount; + + public PayoutAndPerson(String name, Double payoutAmount) { + this.name = name; + this.payoutAmount = payoutAmount; + } + + @Override + public String toString() { + return "PayoutAndPerson{" + + "name='" + name + '\'' + + ", payoutAmount=" + payoutAmount + + '}'; + } +} diff --git a/src/main/java/interviewQuestions/distributeProceeds/PayoutByPerson.java b/src/main/java/interviewQuestions/distributeProceeds/PayoutByPerson.java new file mode 100644 index 0000000..259c107 --- /dev/null +++ b/src/main/java/interviewQuestions/distributeProceeds/PayoutByPerson.java @@ -0,0 +1,11 @@ +package interviewQuestions.distributeProceeds; + +import java.util.List; + +public class PayoutByPerson { + List payoutAndPersonList; + + public PayoutByPerson(List payoutAndPersonList) { + this.payoutAndPersonList = payoutAndPersonList; + } +} diff --git a/src/main/java/interviewQuestions/distributeProceeds/PayoutByShareclass.java b/src/main/java/interviewQuestions/distributeProceeds/PayoutByShareclass.java new file mode 100644 index 0000000..5151e87 --- /dev/null +++ b/src/main/java/interviewQuestions/distributeProceeds/PayoutByShareclass.java @@ -0,0 +1,11 @@ +package interviewQuestions.distributeProceeds; + +import java.util.List; + +public class PayoutByShareclass { + List payOutAndShareClassList; + + public PayoutByShareclass(List payOutAndShareClassList) { + this.payOutAndShareClassList = payOutAndShareClassList; + } +} diff --git a/src/main/java/interviewQuestions/distributeProceeds/Person.java b/src/main/java/interviewQuestions/distributeProceeds/Person.java new file mode 100644 index 0000000..dd1fa52 --- /dev/null +++ b/src/main/java/interviewQuestions/distributeProceeds/Person.java @@ -0,0 +1,45 @@ +package interviewQuestions.distributeProceeds; + +import java.util.HashMap; +import java.util.Map; + +public class Person { + + private String name; + private Map assumedRolesAndShareCount; + private Map assumedRolesAndProceeds; + + public void setAssumedRolesAndProceeds(Map assumedRolesAndProceeds) { + this.assumedRolesAndProceeds = assumedRolesAndProceeds; + } + + public String getName() { + return name; + } + + public Map getAssumedRolesAndProceeds() { + return this.assumedRolesAndProceeds; + } + + public void setAssumedRoles(Map assumedRoles) { + this.assumedRolesAndShareCount = assumedRoles; + } + + public Map getAssumedRolesToShareCount() { + return this.assumedRolesAndShareCount; + } + + public Person(String name) { + this.name = name; + this.assumedRolesAndShareCount = new HashMap<>(); + this.assumedRolesAndProceeds = new HashMap<>(); + } + + public Double getTotalPayout() { + Double total = 0.0; + for (Role role : this.assumedRolesAndProceeds.keySet()) { + total += assumedRolesAndProceeds.get(role); + } + return Math.round(total * 100) / 100.0; + } +} diff --git a/src/main/java/interviewQuestions/distributeProceeds/Role.java b/src/main/java/interviewQuestions/distributeProceeds/Role.java new file mode 100644 index 0000000..7dc17f6 --- /dev/null +++ b/src/main/java/interviewQuestions/distributeProceeds/Role.java @@ -0,0 +1,9 @@ +package interviewQuestions.distributeProceeds; + +public abstract class Role { + public String name; + + public String getName() { + return this.name; + } +} diff --git a/src/main/java/java8tutorials/defaultMethodsForInterfaces/Formula.java b/src/main/java/java8tutorials/defaultMethodsForInterfaces/Formula.java new file mode 100644 index 0000000..4db6c64 --- /dev/null +++ b/src/main/java/java8tutorials/defaultMethodsForInterfaces/Formula.java @@ -0,0 +1,12 @@ +package java8tutorials.defaultMethodsForInterfaces; + +/** + * Created by stevesun on 4/16/17. + */ +public interface Formula { + double calculate(int a); + + default double sqrt(int a) { + return Math.sqrt(a); + } +} diff --git a/src/main/java/java8tutorials/defaultMethodsForInterfaces/FormulaImpl.java b/src/main/java/java8tutorials/defaultMethodsForInterfaces/FormulaImpl.java new file mode 100644 index 0000000..27dccdb --- /dev/null +++ b/src/main/java/java8tutorials/defaultMethodsForInterfaces/FormulaImpl.java @@ -0,0 +1,17 @@ +package java8tutorials.defaultMethodsForInterfaces; + +/** + * Created by stevesun on 4/16/17. + */ +public class FormulaImpl implements Formula { + @Override + public double calculate(int a) { + return sqrt(a*100); + } + + public static void main(String... args) { + Formula formula = new FormulaImpl(); + System.out.println(formula.sqrt(16)); + System.out.println(formula.calculate(100)); + } +} diff --git a/src/main/java/java8tutorials/functionalInterfaces/Converter.java b/src/main/java/java8tutorials/functionalInterfaces/Converter.java new file mode 100644 index 0000000..cc09d85 --- /dev/null +++ b/src/main/java/java8tutorials/functionalInterfaces/Converter.java @@ -0,0 +1,8 @@ +package java8tutorials.functionalInterfaces; + +/** + * Created by stevesun on 4/16/17. + */ +public interface Converter { + T convert(F from); +} diff --git a/src/main/java/java8tutorials/functionalInterfaces/FunctionDemo.java b/src/main/java/java8tutorials/functionalInterfaces/FunctionDemo.java new file mode 100644 index 0000000..0c13945 --- /dev/null +++ b/src/main/java/java8tutorials/functionalInterfaces/FunctionDemo.java @@ -0,0 +1,61 @@ +package java8tutorials.functionalInterfaces; + +import java.util.concurrent.ExecutionException; +import java.util.function.Function; + +public class FunctionDemo { + + public static void main(String... args) throws ExecutionException, InterruptedException { + System.out.println("Program started."); + FunctionDemo main = new FunctionDemo(); + String originalInput = "originalInput"; + String result = main.doWorkInMultipleStepsInSequence(originalInput); + System.out.println("Program ended, result: " + result); + } + + String doWorkInMultipleStepsInSequence(String messageOne) throws InterruptedException { + return doWorkStepTwoAsync(messageOne, doWorkStepTwoFunction); + } + + String doWorkStepTwoAsync(String message, Function doWorkStepTwoFunction) throws InterruptedException { + Thread.sleep(1000); + StringBuilder sb = new StringBuilder(message); + System.out.println("Spent 1 second doing work in Step Two Async function."); + sb.append(",aboutToCallDoWorkStepTwoFunction"); + String intermediateResult = doWorkStepTwoFunction.apply(sb.toString()); + return doWorkStepThreeAsync(intermediateResult, doWorkStepThreeFunction); + } + + String doWorkStepThreeAsync(String message, Function doWorkStepThreeFunction) throws InterruptedException { + Thread.sleep(1000); + StringBuilder sb = new StringBuilder(message); + System.out.println("Spent 1 second doing work in Step Three Async function."); + sb.append(",aboutToCallDoWorkStepThreeFunction"); + return doWorkStepThreeFunction.apply(sb.toString()); + } + + Function doWorkStepTwoFunction = s -> { + StringBuilder sb = new StringBuilder(s); + try { + Thread.sleep(1000); + System.out.println("Spent 1 second doing work in Step Two."); + sb.append(",stepTwoDone"); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return sb.toString(); + }; + + Function doWorkStepThreeFunction = s -> { + StringBuilder sb = new StringBuilder(s); + try { + Thread.sleep(1000); + System.out.println("Spent 1 second doing work in Step Three."); + sb.append(",stepThreeDone"); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return sb.toString(); + }; + +} diff --git a/src/main/java/java8tutorials/functionalInterfaces/FunctionalInterfacesDemo.java b/src/main/java/java8tutorials/functionalInterfaces/FunctionalInterfacesDemo.java new file mode 100644 index 0000000..b0b24ba --- /dev/null +++ b/src/main/java/java8tutorials/functionalInterfaces/FunctionalInterfacesDemo.java @@ -0,0 +1,97 @@ +package java8tutorials.functionalInterfaces; + +import java.util.function.Function; + +public class FunctionalInterfacesDemo { + /** + * How does lambda expressions fit into Javas type system? + * Each lambda corresponds to a given type, specified by an interface. + * A so-called functional interface must contain exactly one abstract method declaration. + * Each lambda expression of that type will be matched to this abstract method. + * Since default methods are not abstract you're free to add default methods to your functional interface. + * We can use arbitrary interfaces as lambda expressions as long as the interface only contains one abstract method. + * To ensure that your interface meet the requirements, + * you should add the @FunctionalInterface annotation. + * The compiler is aware of this annotation and throws a compiler error as soon as you try to add a second abstract method declaration to + * the interface. + */ + + public static void main(String... args) { + Converter converter = (from -> Integer.valueOf(from)); + Integer converted = converter.convert("123"); + System.out.println(converted); + + //we can use :: keyword to simplify the above + //that is how to reference a static method + converter = Integer::valueOf; + converted = converter.convert("321"); + System.out.println(converted); + + runAnotherFunctionInterfaceExample(); + } + + private static void runAnotherFunctionInterfaceExample() { + /**Function interface has a few methods that are often used: + * apply() + * andThen() + * compose() + * identity() + * */ + Function addFunction = a -> a + 3; + System.out.println(addFunction.apply(1)); + + Function multipleFunction = (a) -> a * 3; + System.out.println(multipleFunction.apply(1)); + + //a.compose(b) means b will be executed first and then a will execute + Function compositeFunction = addFunction.compose(multipleFunction); + System.out.println(compositeFunction.apply(1)); + + //a.andThen(b) means a will be executed first, and then function b executes. + Function andThenFunction = addFunction.andThen(multipleFunction); + System.out.println(andThenFunction.apply(1)); + + //Function.identity() is a static method of Function interface that returns a Function that always returns its input argument. i.e. f(x) = x + understandFunctionIdentity(); + } + + private static void understandFunctionIdentity() { + // Using String as Input for Function.identity() + Function stringFunction = Function.identity(); + System.out.println(stringFunction.apply("Alive is Awesome")); + + // Using Integer as input for Function.identity() + Function integerFunctionUsingFunctionIdentity = Function.identity(); + System.out.println(integerFunctionUsingFunctionIdentity.apply(8)); + + // Using lambda expression and String as input + Function stringFunctionUsingLambda = t -> t; + System.out.println(stringFunctionUsingLambda.apply("Be in present")); + + // Using lambda expression and Integer as input + Function integerFunctionUsingLambda = t -> t; + System.out.println(integerFunctionUsingLambda.apply(4)); + + Function func1 = Function.identity(); + Function func2 = Function.identity(); + Function func3 = Function.identity(); + + Function intFunc1 = t -> t; + Function intFunc2 = t -> t; + Function intFunc3 = t -> t; + + System.out.println(func1); + System.out.println(func2); + System.out.println(func3); + + System.out.println(intFunc1); + System.out.println(intFunc2); + System.out.println(intFunc3); + /** + * From the above output, we can conclude that Function.identity() + * method will always return the same instance + * whereas each occurrence of (t -> t) or identifier -> identifier + * will not only create its own instance but even have a distinct implementation class.*/ + } + +} diff --git a/src/main/java/java8tutorials/lamdaExpressions/LamdaDemo.java b/src/main/java/java8tutorials/lamdaExpressions/LamdaDemo.java new file mode 100644 index 0000000..30798bd --- /dev/null +++ b/src/main/java/java8tutorials/lamdaExpressions/LamdaDemo.java @@ -0,0 +1,122 @@ +package java8tutorials.lamdaExpressions; + +import lombok.Getter; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Created by stevesun on 4/16/17. + */ +public class LamdaDemo { + public static void sortInPreJava8() { + List names = Arrays.asList(new Person("Sophie", 27), new Person("Ada", 1), + new Person("Steve", 28), new Person("Eason", 26), new Person("Jenny", 31)); + + print(names, "Prior to sort: "); + + Collections.sort(names, new Comparator() { + @Override + public int compare(Person o1, Person o2) { + return o1.age - o2.age; + } + }); + + print(names, "After sorting: "); + } + + private static void print(List persons, String context) { + System.out.println(context); + for (Person person : persons) { + System.out.println(person.toString()); + } + System.out.println(); + } + + public static void sortInJava8_use_lamda_expressions() { + List names = Arrays.asList(new Person("Sophie", 27), new Person("Ada", 1), + new Person("Steve", 28), new Person("Eason", 26), new Person("Jenny", 31)); + + print(names, "Prior to sort: "); + + Collections.sort(names, (Person a, Person b) -> { + return a.age - b.age; + }); + + print(names, "After sorting: "); + } + + public static void sortInJava8_use_lamda_expressions_shorter() { + List names = Arrays.asList(new Person("Sophie", 27), new Person("Ada", 1), + new Person("Steve", 28), new Person("Eason", 26), new Person("Jenny", 31)); + + print(names, "Prior to sort: "); + + Collections.sort(names, (Person a, Person b) -> a.age - b.age); + + print(names, "After sorting: "); + } + + public static void sortInJava8_use_lamda_expressions_shorter_even() { + List names = Arrays.asList(new Person("Sophie", 27), new Person("Ada", 1), + new Person("Steve", 28), new Person("Eason", 26), new Person("Jenny", 31)); + + print(names, "Prior to sort: "); + + Collections.sort(names, (a, b) -> a.age - b.age); + + print(names, "After sorting: "); + } + + public static void sortInJava8_use_lamda_expressions_and_stream() { + List names = Arrays.asList(new Person("Sophie", 27), new Person("Ada", 1), + new Person("Steve", 28), new Person("Eason", 26), new Person("Jenny", 31)); + + System.out.println("In sortInJava8_use_lamda_expressions_using_stream method."); + print(names, "Prior to sort: "); + + List sorted = names.stream().sorted(Comparator.comparing(Person::getAge)).collect(Collectors.toList()); + + print(sorted, "After sorting: "); + } + + public static void sortInJava8_use_lamda_expressions_and_stream_and_filter() { + List names = Arrays.asList(new Person("Sophie", 27), new Person("Ada", 1), + new Person("Steve", 28), new Person("Eason", 26), new Person("Jenny", 31)); + + System.out.println("In sortInJava8_use_lamda_expressions_and_stream_and_filter method."); + + names.stream().distinct().forEach(System.out::println); + names.stream().map(person -> person.name.charAt(0)).distinct().forEach(System.out::println); + } + + public static void main(String...args) { + sortInPreJava8(); + sortInJava8_use_lamda_expressions(); + sortInJava8_use_lamda_expressions_shorter(); + sortInJava8_use_lamda_expressions_shorter_even(); + sortInJava8_use_lamda_expressions_and_stream(); + sortInJava8_use_lamda_expressions_and_stream_and_filter(); + } +} + +class Person { + String name; + @Getter + int age; + public Person (String name, int age) { + this.name = name; + this.age = age; + } + + @Override + public String toString() { + return "Person{" + + "name='" + name + '\'' + + ", age=" + age + + '}'; + } +} diff --git a/src/main/java/javaConsumerInterfaceExamples/ConsumerInterfaceExample.java b/src/main/java/javaConsumerInterfaceExamples/ConsumerInterfaceExample.java new file mode 100644 index 0000000..a0cf1b9 --- /dev/null +++ b/src/main/java/javaConsumerInterfaceExamples/ConsumerInterfaceExample.java @@ -0,0 +1,42 @@ +package javaConsumerInterfaceExamples; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class ConsumerInterfaceExample { + static void printMessage(String name) { + System.out.println("Hello " + name); + } + + static void printValue(int val) { + System.out.println(val); + } + + static void addList(List list) { + // Return sum of list values + int result = list.stream() + .mapToInt(Integer::intValue) + .sum(); + System.out.println("Sum of list values: " + result); + } + + public static void main(String[] args) { + // Referring method to String type Consumer interface + Consumer consumer1 = ConsumerInterfaceExample::printMessage; + consumer1.accept("John"); // Calling Consumer method + // Referring method to Integer type Consumer interface + Consumer consumer2 = ConsumerInterfaceExample::printValue; + consumer2.accept(12); // Calling Consumer method + + // Creating a list and adding values + List list = new ArrayList<>(); + list.add(10); + list.add(20); + list.add(30); + list.add(40); + // Referring method to String type Consumer interface + Consumer> consumer = ConsumerInterfaceExample::addList; + consumer.accept(list); // Calling Consumer method + } +} diff --git a/src/main/java/javaConsumerInterfaceExamples/MainApp.java b/src/main/java/javaConsumerInterfaceExamples/MainApp.java new file mode 100644 index 0000000..f6baf1f --- /dev/null +++ b/src/main/java/javaConsumerInterfaceExamples/MainApp.java @@ -0,0 +1,10 @@ +package javaConsumerInterfaceExamples; + +import java.util.function.Consumer; + +public class MainApp { + public static void main(String... args) { + Consumer print = x -> System.out.println(x); + print.accept("java 8 consumer interface"); // java + } +} diff --git a/src/main/java/javaSDKExamples/StringFormatAPI.java b/src/main/java/javaSDKExamples/StringFormatAPI.java new file mode 100644 index 0000000..1eaee91 --- /dev/null +++ b/src/main/java/javaSDKExamples/StringFormatAPI.java @@ -0,0 +1,28 @@ +package javaSDKExamples; + +public class StringFormatAPI { + + public static void main(String... args) { + /**https://www.javatpoint.com/java-string-format + * %d decimal integer + * %x hex string, %06x means padding up to 6 leading zeroes to make it 6 digits + * %s string value + * + * */ + final String actual = String.format( + "coolString%d%c%02d%02d%02d%02d%06x%012x%s%s", + 1, + 'a', + 17, + 3, + 9, + 3, + 1234, + 1234567890, + "4_abc_12", + "" + ); + System.out.println("actual is: " + actual); + } + +} diff --git a/src/main/java/java_async_method_example/async/method/MainApp.java b/src/main/java/java_async_method_example/async/method/MainApp.java new file mode 100644 index 0000000..a470ae1 --- /dev/null +++ b/src/main/java/java_async_method_example/async/method/MainApp.java @@ -0,0 +1,8 @@ +package java_async_method_example.async.method; + +public class MainApp { + + public static void main(String... args) { + System.out.println("That's the end of MainApp!"); + } +} diff --git a/src/sporadic/java_async_method_example/future/MainApp.java b/src/main/java/java_async_method_example/future/MainApp.java similarity index 87% rename from src/sporadic/java_async_method_example/future/MainApp.java rename to src/main/java/java_async_method_example/future/MainApp.java index b3201f1..c4e2692 100644 --- a/src/sporadic/java_async_method_example/future/MainApp.java +++ b/src/main/java/java_async_method_example/future/MainApp.java @@ -1,4 +1,4 @@ -package sporadic.java_async_method_example.future; +package java_async_method_example.future; import java.util.ArrayList; import java.util.Date; @@ -17,10 +17,10 @@ public static void main(String... args) { // Executors.newSingleThreadExecutor() // Executors.newCachedThreadPool() Executors.newScheduledThreadPool(15); - /**thread pool account could be a bottleneck when it's smaller than 10 which is the max in the below for loop. + /**thread pool count could be a bottleneck when it's smaller than 10 which is the max in the below for loop. * so when I changed the ThreadPool size to 15, then ALL Future objects got returned at the same time! Cool!*/ - List> list = new ArrayList>(); + List> list = new ArrayList<>(); Callable callable = new MyCallable(); diff --git a/src/sporadic/java_async_method_example/future/MyCallable.java b/src/main/java/java_async_method_example/future/MyCallable.java similarity index 91% rename from src/sporadic/java_async_method_example/future/MyCallable.java rename to src/main/java/java_async_method_example/future/MyCallable.java index a2eebcc..2e9669d 100644 --- a/src/sporadic/java_async_method_example/future/MyCallable.java +++ b/src/main/java/java_async_method_example/future/MyCallable.java @@ -1,4 +1,4 @@ -package sporadic.java_async_method_example.future; +package java_async_method_example.future; import java.util.concurrent.Callable; diff --git a/src/main/java/java_collections/HashMapDemo.java b/src/main/java/java_collections/HashMapDemo.java new file mode 100644 index 0000000..bd84588 --- /dev/null +++ b/src/main/java/java_collections/HashMapDemo.java @@ -0,0 +1,37 @@ +package java_collections; + +import java.util.Map; + +public class HashMapDemo { + private static final int NUMBER_OF_MAP_ENTRIES = 2; + + public static void main(String... args) { + System.out.println("Program started."); + HashMapDemo hashMapDemo = new HashMapDemo(); + hashMapDemo.understandHashMapInternalWorkings(); + System.out.println("Program finished."); + } + + private void understandHashMapInternalWorkings() { + /**This arcitle says it pretty well: https://levelup.gitconnected.com/internal-working-of-hashmap-in-java-latest-updated-4c2708f76d2c + * 1. HashMap uses its static inner class Node for storing map entries. That means each entry in hashMap is a Node. + * 2. Internally HashMap uses a hashCode of the key Object and this hashCode is further used by the hash function to find the index of the bucket where the new entry can be added. + * 3. HashMap uses multiple buckets and each bucket points to a Singly Linked List where the entries (nodes) are stored. + * 4. Once the bucket is identified by the hash function using hashcode, then hashCode is used to check if there is already a key with the same hashCode or not in the bucket (I mean corresponding singly linked list). + * If there already exists a key with the same hashCode, then the equals() method is used on the keys. + * If the equals method returns true, that means there is already a node with the same key and hence the value against that key is overwritten in the entry (node), + * otherwise, a new node is created and added to this Singly Linked List of that bucket. + * If there is no key with the same hashCode in the bucket found by the hash function then the new Node is added to the bucket found. + * 5. There's a threshold after which is reached, HashMap will change from using singly linked list to use a self-balancing BST, static final int TREEIFY_THRESHOLD = 8; + * the motive for this change is that it could take O(n) worst case for look up with linked list, however, with a self-balancing BST, e.g. red-black tree, we could get O(logn) lookup time; + * + * To have a high-performance hashMap we need good implementation of hashCode() and equals() method along with hash function. + * */ + Map map = new java.util.HashMap<>(); + for (int i = 0; i < NUMBER_OF_MAP_ENTRIES; i++) { + map.put("key" + i, "value" + i); + } + map.put("key1", "value_new"); + System.out.println("this method finishes."); + } +} diff --git a/src/main/java/java_collections/HashSetDemo.java b/src/main/java/java_collections/HashSetDemo.java new file mode 100644 index 0000000..cd98ee1 --- /dev/null +++ b/src/main/java/java_collections/HashSetDemo.java @@ -0,0 +1,32 @@ +package java_collections; + +import java.util.HashSet; +import java.util.Set; + +public class HashSetDemo { + + private static final int NUMBER_OF_SET_ENTRIES = 2; + + public static void main(String... args) { + System.out.println("Program started."); + HashSetDemo hashSetDemo = new HashSetDemo(); + hashSetDemo.understandHashSetInternalWorkings(); + System.out.println("Program finished."); + } + + private void understandHashSetInternalWorkings() { + /** + * 1. Internally, Java uses a HashMap to implement HashSet, it just inserts a dummy object as value into the map: private static final Object PRESENT = new Object(); + * you can step into the java.util.HashSet library to see this: + * public boolean add(E e) { + * return map.put(e, PRESENT)==null; + * } + * 2. https://medium.com/javarevisited/internal-working-of-hashset-in-java-interview-question-129bdd31fc60 for more references/ + * */ + Set set = new HashSet<>(); + for (int i = 0; i < NUMBER_OF_SET_ENTRIES; i++) { + set.add(i + ""); + } + System.out.println("Method finishes."); + } +} diff --git a/src/sporadic/java_generics/GenericClass.java b/src/main/java/java_generics/GenericClass.java similarity index 91% rename from src/sporadic/java_generics/GenericClass.java rename to src/main/java/java_generics/GenericClass.java index 6d7c2ec..f118b97 100644 --- a/src/sporadic/java_generics/GenericClass.java +++ b/src/main/java/java_generics/GenericClass.java @@ -1,4 +1,4 @@ -package sporadic.java_generics; +package java_generics; /** * This is a generic class that operates on objects of only T diff --git a/src/sporadic/java_generics/MainApp.java b/src/main/java/java_generics/MainApp.java similarity index 93% rename from src/sporadic/java_generics/MainApp.java rename to src/main/java/java_generics/MainApp.java index 79fb69a..daa3213 100644 --- a/src/sporadic/java_generics/MainApp.java +++ b/src/main/java/java_generics/MainApp.java @@ -1,4 +1,4 @@ -package sporadic.java_generics; +package java_generics; /** * Created by stevesun on 12/7/16. diff --git a/src/sporadic/java_generics/NonGenericClass.java b/src/main/java/java_generics/NonGenericClass.java similarity index 88% rename from src/sporadic/java_generics/NonGenericClass.java rename to src/main/java/java_generics/NonGenericClass.java index ab7ee45..79013f0 100644 --- a/src/sporadic/java_generics/NonGenericClass.java +++ b/src/main/java/java_generics/NonGenericClass.java @@ -1,4 +1,4 @@ -package sporadic.java_generics; +package java_generics; /** * This is a non-generic Box class that operates on objects of any type. */ diff --git a/src/sporadic/java_generics/ParentClass.java b/src/main/java/java_generics/ParentClass.java similarity index 92% rename from src/sporadic/java_generics/ParentClass.java rename to src/main/java/java_generics/ParentClass.java index d48b31a..d2be750 100644 --- a/src/sporadic/java_generics/ParentClass.java +++ b/src/main/java/java_generics/ParentClass.java @@ -1,4 +1,4 @@ -package sporadic.java_generics; +package java_generics; public class ParentClass { diff --git a/src/main/java/java_playground/MainApp.java b/src/main/java/java_playground/MainApp.java new file mode 100644 index 0000000..0bc44e6 --- /dev/null +++ b/src/main/java/java_playground/MainApp.java @@ -0,0 +1,8 @@ +package java_playground; + +public class MainApp { + public static void main(String... args) { + System.out.println("Hello world."); + System.out.println("Program finished."); + } +} diff --git a/src/main/java/java_streams/StreamsExample.java b/src/main/java/java_streams/StreamsExample.java new file mode 100644 index 0000000..82af461 --- /dev/null +++ b/src/main/java/java_streams/StreamsExample.java @@ -0,0 +1,43 @@ +package java_streams; + +import java.util.Arrays; +import java.util.List; + +public class StreamsExample { + public static void main(String... args) { + /**reference: https://www.baeldung.com/java-when-to-use-parallel-stream*/ + System.out.println("Program started."); + sequentialStreams(); + parallelStreams(); + System.out.println("Program ended."); + } + + private static void sequentialStreams() { + /**By default, any stream operation in Java is processed sequentially, unless explicitly specified as parallel. + Sequential streams use a single thread to process the pipeline like below: + */ + List listOfNumbers = Arrays.asList(1, 2, 3, 4); + listOfNumbers.stream().forEach(number -> + System.out.println(number + " from this thread: " + Thread.currentThread().getName()) + ); + } + + private static void parallelStreams() { + /** + * Any stream in Java can easily be transformed from sequential to parallel. + * We can achieve this by adding the parallel method to a sequential stream or by creating a stream using the parallelStream method of a collection: + * */ + List listOfNumbers = Arrays.asList(5, 6, 7, 8); + listOfNumbers.parallelStream().forEach(number -> + System.out.println(number + " from this thread: " + Thread.currentThread().getName()) + ); + /** + * Parallel streams enable us to execute code in parallel on separate cores. + * The final result is the combination of each individual outcome. + * However, the order of execution is out of our control.*/ + + /** + * Parallel streams make use of the fork-join framework and its common pool of worker threads. + * The fork-join framework was added to java.util.concurrent in Java 7 to handle task management between multiple threads.*/ + } +} diff --git a/src/main/java/java_volatile/TaskRunner.java b/src/main/java/java_volatile/TaskRunner.java new file mode 100644 index 0000000..c5cf879 --- /dev/null +++ b/src/main/java/java_volatile/TaskRunner.java @@ -0,0 +1,37 @@ +package java_volatile; + +public class TaskRunner { + /** + * This is following the examples from https://www.baeldung.com/java-volatile + * + * Volatile keyword is to deal with Java Memory Model cache coherent challenges: + * To ensure that updates to variables propagate predictably to other threads, we should apply the volatile modifier to those variables. + * This way, we can communicate with runtime and processor to not reorder any instruction involving the volatile variable. + * Also, processors understand that they should immediately flush any updates to these variables so that other threads could read the shared variables most up-to-date values. + */ + private static int number; + private volatile static boolean ready; + + private static class Reader extends Thread { + @Override + public void run() { + System.out.println(Thread.currentThread().getName() + " thread says, ready = " + ready); + while (!ready) { + System.out.println(Thread.currentThread().getName() + " is yielding now.."); + Thread.yield(); + } + System.out.println(Thread.currentThread().getName() + " thread says, number = " + number); + } + } + + public static void main(String[] args) throws InterruptedException { + System.out.println(Thread.currentThread().getName() + " thread started now..."); + new Reader().start(); + System.out.println(Thread.currentThread().getName() + " thread is running now..."); + number = 42; + Thread.sleep(6); + System.out.println(Thread.currentThread().getName() + " thread finishes sleeping."); + ready = true; + System.out.println(Thread.currentThread().getName() + " thread finished."); + } +} diff --git a/src/sporadic/jsonExample/JsonDemoClass.java b/src/main/java/jsonExample/JsonDemoClass.java similarity index 59% rename from src/sporadic/jsonExample/JsonDemoClass.java rename to src/main/java/jsonExample/JsonDemoClass.java index 8f8154c..bfa4687 100644 --- a/src/sporadic/jsonExample/JsonDemoClass.java +++ b/src/main/java/jsonExample/JsonDemoClass.java @@ -1,4 +1,4 @@ -package sporadic.jsonExample; +package jsonExample; import org.codehaus.jackson.annotate.JsonIgnore; import org.codehaus.jackson.annotate.JsonIgnoreProperties; @@ -6,9 +6,7 @@ import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; -import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.Setter; import lombok.ToString; /**This package is to demo how @JsonIgnore and @JsonIgnorProperties and @JsonProperty work: @@ -22,27 +20,57 @@ @ToString @JsonIgnoreProperties({"noInterestingMember", "forgetThisField"}) public class JsonDemoClass { - @Getter - @Setter + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getNoInterestingMember() { + return noInterestingMember; + } + + public void setNoInterestingMember(String noInterestingMember) { + this.noInterestingMember = noInterestingMember; + } + + public int getAnotherMember() { + return anotherMember; + } + + public void setAnotherMember(int anotherMember) { + this.anotherMember = anotherMember; + } + + public double getForgetThisField() { + return forgetThisField; + } + + public void setForgetThisField(double forgetThisField) { + this.forgetThisField = forgetThisField; + } + @JsonProperty("ID") public long id; - - @Getter - @Setter + @JsonProperty("NAME") public String name; - - @Getter - @Setter + public String noInterestingMember; - - @Getter - @Setter + @JsonIgnore @JsonProperty("ANOTHER-MEMEBR") public int anotherMember; - - @Getter - @Setter + public double forgetThisField; } \ No newline at end of file diff --git a/src/sporadic/jsonExample/JsonIgnoreAnnotationDemo.java b/src/main/java/jsonExample/JsonIgnoreAnnotationDemo.java similarity index 97% rename from src/sporadic/jsonExample/JsonIgnoreAnnotationDemo.java rename to src/main/java/jsonExample/JsonIgnoreAnnotationDemo.java index 9a88e68..dcaa97f 100644 --- a/src/sporadic/jsonExample/JsonIgnoreAnnotationDemo.java +++ b/src/main/java/jsonExample/JsonIgnoreAnnotationDemo.java @@ -1,4 +1,4 @@ -package sporadic.jsonExample; +package jsonExample; import java.io.IOException; diff --git a/src/learnHeadFirstJava/another_serialization_example/DeseriliazeDemo.java b/src/main/java/learnHeadFirstJava/another_serialization_example/DeseriliazeDemo.java similarity index 100% rename from src/learnHeadFirstJava/another_serialization_example/DeseriliazeDemo.java rename to src/main/java/learnHeadFirstJava/another_serialization_example/DeseriliazeDemo.java diff --git a/src/learnHeadFirstJava/another_serialization_example/Employee.java b/src/main/java/learnHeadFirstJava/another_serialization_example/Employee.java similarity index 69% rename from src/learnHeadFirstJava/another_serialization_example/Employee.java rename to src/main/java/learnHeadFirstJava/another_serialization_example/Employee.java index f841037..c4992bd 100644 --- a/src/learnHeadFirstJava/another_serialization_example/Employee.java +++ b/src/main/java/learnHeadFirstJava/another_serialization_example/Employee.java @@ -6,9 +6,7 @@ import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; -import lombok.Getter; import lombok.RequiredArgsConstructor; -import lombok.Setter; //Any one of the following three annotations: @Service, @Repository and @Component will work fine here since I'm doing a component-scan. //@Component @@ -16,20 +14,51 @@ @Service @RequiredArgsConstructor public class Employee implements Serializable { - @Setter - @Getter private String address; - @Setter - @Getter + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public double getSalary() { + return salary; + } + + public void setSalary(double salary) { + this.salary = salary; + } + + public int getSSN() { + return SSN; + } + + public void setSSN(int SSN) { + this.SSN = SSN; + } + private String name; - @Setter - @Getter private int age; - @Setter - @Getter private double salary; - @Setter - @Getter private transient int SSN;// any field that cannot be serialized needs to be // marked as transient, for demo purpose, we // just set SSN as a non-serializable field, it diff --git a/src/learnHeadFirstJava/another_serialization_example/MainApp.java b/src/main/java/learnHeadFirstJava/another_serialization_example/MainApp.java similarity index 100% rename from src/learnHeadFirstJava/another_serialization_example/MainApp.java rename to src/main/java/learnHeadFirstJava/another_serialization_example/MainApp.java diff --git a/src/learnHeadFirstJava/another_serialization_example/SerializeDemo.java b/src/main/java/learnHeadFirstJava/another_serialization_example/SerializeDemo.java similarity index 100% rename from src/learnHeadFirstJava/another_serialization_example/SerializeDemo.java rename to src/main/java/learnHeadFirstJava/another_serialization_example/SerializeDemo.java diff --git a/src/learnHeadFirstJava/constructorChaining/Animal.java b/src/main/java/learnHeadFirstJava/constructorChaining/Animal.java similarity index 100% rename from src/learnHeadFirstJava/constructorChaining/Animal.java rename to src/main/java/learnHeadFirstJava/constructorChaining/Animal.java diff --git a/src/learnHeadFirstJava/constructorChaining/Creature.java b/src/main/java/learnHeadFirstJava/constructorChaining/Creature.java similarity index 100% rename from src/learnHeadFirstJava/constructorChaining/Creature.java rename to src/main/java/learnHeadFirstJava/constructorChaining/Creature.java diff --git a/src/learnHeadFirstJava/constructorChaining/Dog.java b/src/main/java/learnHeadFirstJava/constructorChaining/Dog.java similarity index 100% rename from src/learnHeadFirstJava/constructorChaining/Dog.java rename to src/main/java/learnHeadFirstJava/constructorChaining/Dog.java diff --git a/src/learnHeadFirstJava/constructorChaining/MainApp.java b/src/main/java/learnHeadFirstJava/constructorChaining/MainApp.java similarity index 100% rename from src/learnHeadFirstJava/constructorChaining/MainApp.java rename to src/main/java/learnHeadFirstJava/constructorChaining/MainApp.java diff --git a/src/learnHeadFirstJava/constructorChaining/Pet.java b/src/main/java/learnHeadFirstJava/constructorChaining/Pet.java similarity index 100% rename from src/learnHeadFirstJava/constructorChaining/Pet.java rename to src/main/java/learnHeadFirstJava/constructorChaining/Pet.java diff --git a/src/learnHeadFirstJava/serializationIsFun/GospelBook.java b/src/main/java/learnHeadFirstJava/serializationIsFun/GospelBook.java similarity index 100% rename from src/learnHeadFirstJava/serializationIsFun/GospelBook.java rename to src/main/java/learnHeadFirstJava/serializationIsFun/GospelBook.java diff --git a/src/learnHeadFirstJava/serializationIsFun/GospelSaverTest.java b/src/main/java/learnHeadFirstJava/serializationIsFun/GospelSaverTest.java similarity index 100% rename from src/learnHeadFirstJava/serializationIsFun/GospelSaverTest.java rename to src/main/java/learnHeadFirstJava/serializationIsFun/GospelSaverTest.java diff --git a/src/sporadic/method_invoke_and_reflect/Deet.java b/src/main/java/method_invoke_and_reflect/Deet.java similarity index 98% rename from src/sporadic/method_invoke_and_reflect/Deet.java rename to src/main/java/method_invoke_and_reflect/Deet.java index 99d4a6f..b60e286 100644 --- a/src/sporadic/method_invoke_and_reflect/Deet.java +++ b/src/main/java/method_invoke_and_reflect/Deet.java @@ -1,4 +1,4 @@ -package sporadic.method_invoke_and_reflect; +package method_invoke_and_reflect; import static java.lang.System.err; import static java.lang.System.out; diff --git a/src/main/java/multithread/CompletionServiceDemo.java b/src/main/java/multithread/CompletionServiceDemo.java new file mode 100644 index 0000000..58cca21 --- /dev/null +++ b/src/main/java/multithread/CompletionServiceDemo.java @@ -0,0 +1,87 @@ +package multithread; + +import java.util.concurrent.*; + +public class CompletionServiceDemo { + /** + * credit: https://stackoverflow.com/a/5580058/4117496 + */ + class CalcResult { + long result; + + CalcResult(long l) { + result = l; + } + } + + class CallableTask implements Callable { + String taskName; + long input1; + int input2; + + CallableTask(String name, long v1, int v2) { + taskName = name; + input1 = v1; + input2 = v2; + } + + public CalcResult call() { + System.out.println("Task " + taskName + " started -----"); + for (int i = 0; i < input2; i++) { + try { + Thread.sleep(200); + } catch (InterruptedException e) { + System.out.println("Task " + taskName + " interrupted !! "); + e.printStackTrace(); + } + input1 += i; + } + System.out.println("Task " + taskName + " completed."); + return new CalcResult(input1); + } + + } + + public void test() { + ExecutorService executorService = Executors.newFixedThreadPool(3); + CompletionService completionService = new ExecutorCompletionService<>(executorService); + + int submittedTasks = 5; + for (int i = 0; i < submittedTasks; i++) { + completionService.submit(new CallableTask( + String.valueOf(i), + (i * 10), + ((i * 10) + 10) + )); + System.out.println("Task " + i + " submitted"); + } + for (int tasksHandled = 0; tasksHandled < submittedTasks; tasksHandled++) { + try { + System.out.println("trying to take from Completion service"); + Future result = completionService.take(); + System.out.println("result for a task available in queue. Trying to get() now"); + // above call blocks till atleast one task is completed and results availble for it + // but we don't have to worry which one + + // process the result here by doing result.get() + CalcResult l = result.get(); + System.out.println("Task " + tasksHandled + " completed - results obtained : " + l.result); + + } catch (InterruptedException e) { + // Something went wrong with a task submitted + System.out.println("Error Interrupted exception"); + e.printStackTrace(); + } catch (ExecutionException e) { + // Something went wrong with the result + e.printStackTrace(); + System.out.println("Error get() threw exception"); + } + } + } + + public static void main(String... args) { + CompletionServiceDemo demo = new CompletionServiceDemo(); + demo.test(); + System.out.println("\n\nProgram finished.\n"); + } +} diff --git a/src/sporadic/thread/HusbandAndWifeJob.java b/src/main/java/multithread/HusbandAndWifeJob.java similarity index 74% rename from src/sporadic/thread/HusbandAndWifeJob.java rename to src/main/java/multithread/HusbandAndWifeJob.java index 6664f9c..5d06722 100644 --- a/src/sporadic/thread/HusbandAndWifeJob.java +++ b/src/main/java/multithread/HusbandAndWifeJob.java @@ -1,4 +1,4 @@ -package sporadic.thread; +package multithread; public class HusbandAndWifeJob implements Runnable { @@ -9,6 +9,7 @@ public class HusbandAndWifeJob implements Runnable { */ @Override public void run() { + for (int i = 0; i < 10; i++) { makeWithdrawl(10); if (bankAccount.getBalance() < 0) { @@ -25,13 +26,16 @@ public void run() { private synchronized void makeWithdrawl(int amount) { if (bankAccount.getBalance() >= amount) { System.out.println(Thread.currentThread().getName() + " is about to withdraw: " + amount); - try { - System.out.println(Thread.currentThread().getName() + " is going to sleep."); - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - System.out.println(Thread.currentThread().getName() + " woke up."); + +// this sleep block is trying to slow down the work and let you visualize what and how events occur: two threads will call makeWithdrawl() method randomly based on how the scheduler schedules it,wec you can comment it out +// try { +// System.out.println(Thread.currentThread().getName() + " is going to sleep."); +// Thread.sleep(1000); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// System.out.println(Thread.currentThread().getName() + " woke up."); + bankAccount.withdraw(amount); System.out.println(Thread.currentThread().getName() + " finished withdrawl: " + amount + "\t now the balance is: " + bankAccount.getBalance()); } else { @@ -56,7 +60,7 @@ public static void main(String[] args) { } class BankAccount { - private int balance = 100000; + private int balance = 100; public int getBalance() { return balance; diff --git a/src/main/java/multithread/OneThreadDemo.java b/src/main/java/multithread/OneThreadDemo.java new file mode 100644 index 0000000..df978f8 --- /dev/null +++ b/src/main/java/multithread/OneThreadDemo.java @@ -0,0 +1,20 @@ +package multithread; + +public class OneThreadDemo { + static class MeaninglessClass { + public void meaninglessMethod() { + System.out.println("In meaninglessMethod method now, current thread name is: " + Thread.currentThread().getName()); + } + } + + public static void main(String... args) { + /**This is to show that this program will guarantee to run in just one thread: main, there's no multi-threading here.*/ + MeaninglessClass meaninglessClass = new MeaninglessClass(); + meaninglessClass.meaninglessMethod(); + meaninglessClass.meaninglessMethod(); + meaninglessClass.meaninglessMethod(); + meaninglessClass.meaninglessMethod(); + meaninglessClass.meaninglessMethod(); + System.out.println("Program finished."); + } +} diff --git a/src/main/java/multithread/ThreadIsCool.java b/src/main/java/multithread/ThreadIsCool.java new file mode 100644 index 0000000..a7ae96b --- /dev/null +++ b/src/main/java/multithread/ThreadIsCool.java @@ -0,0 +1,70 @@ +package multithread; + +/** + * This is a cool and small program to show that threads run order could be controlled by using Thread.join() method. + */ + +public class ThreadIsCool implements Runnable { + + public static void main(String[] args) { + ThreadIsCool threadIsCool = new ThreadIsCool(); + Thread thread1 = new Thread(threadIsCool); + Thread thread2 = new Thread(threadIsCool); + Thread thread3 = new Thread(threadIsCool); + Thread thread4 = new Thread(threadIsCool); + thread1.setName("Thread 1"); + thread2.setName("Thread 2"); + thread3.setName("Thread 3"); + thread4.setName("Thread 4"); + System.out.println("Now all the threads are about to kick off:"); + + thread1.start(); + try { + /* Wait for this thread to die before other invocations*/ + thread1.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + thread2.start(); + try { + /* Wait for this thread to die before other invocations*/ + thread2.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + thread3.start(); + try { + /* Wait for this thread to die before other invocations*/ + thread3.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + thread4.start(); + try { + /* Wait for this thread to die before other invocations*/ + thread4.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("Now the Program ended."); + } + + @Override + public void run() { + for (int i = 0; i < 10; i++) { + String threadName = Thread.currentThread().getName(); + System.out.println(threadName + " is running!"); + } + System.out.println(Thread.currentThread().getName() + " is sleeping for 1 second"); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println(Thread.currentThread().getName() + " run finished."); + } + +} diff --git a/src/main/java/multithread/ThreadLocalExample.java b/src/main/java/multithread/ThreadLocalExample.java new file mode 100644 index 0000000..1a4c1b7 --- /dev/null +++ b/src/main/java/multithread/ThreadLocalExample.java @@ -0,0 +1,53 @@ +package multithread; + +/** + * The ThreadLocal class in Java enables you to create variables that can only + * be read and written by the same thread. Thus, even if two threads are + * executing the same code, and the code has a reference to a ThreadLocal + * variable, then the two threads cannot see each other's ThreadLocal variables. + *

+ * Since values set on a ThreadLocal object only are visible to the thread who + * set the value, no thread can set an initial value on a ThreadLocal using + * set() which is visible to all threads. + * Instead you can specify an initial value for a ThreadLocal object by + * subclassing ThreadLocal and overriding the initialValue() method. Here is how + * that looks: + *

+ * private ThreadLocal myThreadLocal = new ThreadLocal() { + * + * @Override protected String initialValue() { return "This is the initial value"; } + * }; + */ + +public class ThreadLocalExample { + + public static class MyRunnable implements Runnable { + + private ThreadLocal threadLocal = new ThreadLocal<>(); + + @Override + public void run() { + Integer value = (int) (Math.random() * 100D); + System.out.println("value = " + value); + threadLocal.set(value); + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("threadLocal.get() is: " + threadLocal.get()); + } + + } + + public static void main(String... args) { + System.out.println("Program started."); + MyRunnable sharedRunnableInstance = new MyRunnable(); + Thread t1 = new Thread(sharedRunnableInstance); + Thread t2 = new Thread(sharedRunnableInstance); + t1.start(); + t2.start(); + System.out.println("Program finished."); + } + +} diff --git a/src/main/java/multithread/WaitNotifyExample.java b/src/main/java/multithread/WaitNotifyExample.java new file mode 100644 index 0000000..c6b24ed --- /dev/null +++ b/src/main/java/multithread/WaitNotifyExample.java @@ -0,0 +1,56 @@ +package multithread; + +public class WaitNotifyExample { + private String packet; + + // True if receiver should wait + // False if sender should wait + private boolean transfer = true; + + public synchronized String receive() { + System.out.println("In receive method now, transfer: " + transfer); + while (transfer) { + try { + System.out.println("waiting to receive now."); + wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + System.out.println("Thread Interrupted"); + } + } + transfer = true; + + String returnPacket = packet; + System.out.println("In receive method, notifyAll now."); + notifyAll(); + System.out.println("In receive method now, returnPacket: " + returnPacket); + return returnPacket; + } + + public synchronized void send(String packet) { + System.out.println("In send method now, transfer: " + transfer); + while (!transfer) { + try { + System.out.println("waiting to send now."); + wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + System.out.println("Thread Interrupted"); + } + } + transfer = false; + + this.packet = packet; + System.out.println("In send method, notifyAll now."); + notifyAll(); + System.out.println("In send method now, packet: " + packet); + } + + public static void main(String... args) { + System.out.println("Hello world..."); + WaitNotifyExample waitNotifyExample = new WaitNotifyExample(); + waitNotifyExample.send("This is a nice test packet.."); + waitNotifyExample.receive(); + System.out.println("Program finished..."); + } +} diff --git a/src/main/java/multithread/Worker.java b/src/main/java/multithread/Worker.java new file mode 100644 index 0000000..3e23e31 --- /dev/null +++ b/src/main/java/multithread/Worker.java @@ -0,0 +1,67 @@ +package multithread; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Created by stevesun on 1/29/17. + */ +public class Worker implements Runnable { + public boolean running = false; + + @Override + public void run() { + this.running = true; + System.out.println("Thread " + Thread.currentThread().getName() + " is running."); + + try { + //this pauses this spawned thread to sleep for 5 seconds. + System.out.println("Thread " + Thread.currentThread().getName() + " sleeps for 3 seconds"); + Thread.sleep(3000); + } catch (InterruptedException e) { + //an InterruptedException should never be swallowed + Thread.currentThread().interrupt(); + } + this.running = false; + System.out.println("Thread " + Thread.currentThread().getName() + " is no longer running."); + } + + + public static void main(String... args) throws InterruptedException { + Worker mainThreadWorker = new Worker(); + List workers = new ArrayList<>(); + + System.out.println("Main thread is running with thread ID: " + Thread.currentThread().getName()); + + Date start = new Date(); + + //let's start 10 workers + for (int i = 0; i < 10; i++) { + System.out.println("i = " + i); + Thread thread = new Thread(mainThreadWorker); + thread.setName(i + ""); + workers.add(thread); + thread.start(); + + //with this join() method, all 10 threads will be invoked in sequence, without it, all 10 threads will run in parallel. + //thread.join(); + } + System.out.println("There's a total of " + workers.size() + " threads."); + + //now we need to force the MAIN thread to wait until all Worker threads end, so we could calculate the duration + for (Thread worker : workers) { + System.out.println("Checking thread " + worker.currentThread().getName() + " now."); + System.out.println("worker.isAlive() = " + worker.isAlive()); + while (worker.isAlive()) { + Thread.sleep(1000); + } + } + + Date end = new Date(); + + Long duration = end.getTime() - start.getTime(); + + System.out.println("This whole process took " + duration / 1000 + " seconds."); + } +} diff --git a/src/main/java/multithread/completablefutureexamples/CompletableFutureDemo.java b/src/main/java/multithread/completablefutureexamples/CompletableFutureDemo.java new file mode 100644 index 0000000..e1a49a5 --- /dev/null +++ b/src/main/java/multithread/completablefutureexamples/CompletableFutureDemo.java @@ -0,0 +1,65 @@ +package multithread.completablefutureexamples; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import static org.junit.Assert.assertEquals; + +public class CompletableFutureDemo { + private static final int MILLISECONDS_TO_FINISH_A_TASK = 1000; + + + public static void main(String... args) throws Exception { + System.out.println("Program started."); + runApp(); + System.out.println("Program ended."); + } + + private static void runApp() throws InterruptedException, ExecutionException { + Future completableFuture = calculateAsync(); + System.out.println("got completableFuture: " + completableFuture); + System.out.println("got completableFuture.isDone(): " + completableFuture.isDone()); + String result = completableFuture.get(); + System.out.println("got completableFuture.isDone(): " + completableFuture.isDone()); + assertEquals("Hello", result); + } + + private static Future calculateAsync() { + CompletableFuture completableFuture = new CompletableFuture<>(); + + Executors.newCachedThreadPool().submit(() -> { + System.out.println("Doing some work in the thread now.."); + Thread.sleep(1000); + System.out.println("Almost done working in the thread now.."); + completableFuture.complete("Hello"); + return null; + }); + + return completableFuture; + } + + static class Worker implements Runnable { + private String workerName; + + public Worker(String workerName) { + this.workerName = workerName; + } + + @Override + public void run() { + System.out.println(Thread.currentThread().getName() + " starting worker: " + workerName); + doWork(); + System.out.println(Thread.currentThread().getName() + " ended for worker: " + workerName); + } + + private void doWork() { + try { + Thread.sleep(MILLISECONDS_TO_FINISH_A_TASK); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } +} diff --git a/src/main/java/multithread/completablefutureexamples/CompletableFutureDemo2.java b/src/main/java/multithread/completablefutureexamples/CompletableFutureDemo2.java new file mode 100644 index 0000000..88135b0 --- /dev/null +++ b/src/main/java/multithread/completablefutureexamples/CompletableFutureDemo2.java @@ -0,0 +1,74 @@ +package multithread.completablefutureexamples; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import static multithread.completablefutureexamples.CompletableFutureDemo2.WorkerPool.TIME_FOR_A_COMPUTATION_JOB_IN_MS; + +public class CompletableFutureDemo2 { + + private static final int POOL_SIZE = 10; + private static final int NUMBER_OF_COMPUTATION_JOBS = 20; + + public static void main(String... args) throws ExecutionException, InterruptedException { + System.out.println("Program started."); + long start = System.currentTimeMillis(); + WorkerPool workerPool = new WorkerPool(POOL_SIZE); + int finalResult = 0; + List> futureList = new ArrayList<>(); + for (int i = 1; i <= NUMBER_OF_COMPUTATION_JOBS; i++) { + Future completableFuture = workerPool.executeAsync(i); + System.out.println("i = " + i + " and completableFuture.isDone() is: " + completableFuture.isDone()); + futureList.add(completableFuture); + } + for (Future future : futureList) { + String result = future.get(); + finalResult += Integer.parseInt(result); + } + long end = System.currentTimeMillis(); + System.out.println("end time in millis: " + end); + System.out.println("start time in millis: " + start); + System.out.println("It took " + (end - start) / 1000 + + " seconds to complete computation, final result: " + finalResult + + ", a total of " + NUMBER_OF_COMPUTATION_JOBS + " computation jobs " + + "have been completed, total pool worker size is: " + POOL_SIZE + + ", and each job took " + TIME_FOR_A_COMPUTATION_JOB_IN_MS / 1000 + " second(s)." + ); + System.out.println("Program ended."); + } + + static class WorkerPool { + static final long TIME_FOR_A_COMPUTATION_JOB_IN_MS = 1000l; + int poolSize; + ExecutorService executorService; + + public WorkerPool(int poolSize) { + this.poolSize = poolSize; + this.executorService = Executors.newFixedThreadPool(poolSize); + } + + public Future executeAsync(int input) { + final CompletableFuture completableFuture = new CompletableFuture<>(); + this.executorService.submit(() -> doWork(completableFuture, input)); + return completableFuture; + } + + private void doWork(CompletableFuture completableFuture, int input) { + int result = 0; + try { + System.out.println(Thread.currentThread().getName() + " is doing some real work now that'll take 1 second to complete."); + Thread.sleep(TIME_FOR_A_COMPUTATION_JOB_IN_MS); + result += input * 2; + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + completableFuture.complete("" + result); + } + } + +} diff --git a/src/main/java/multithread/singlevsmultiplethreads/MultiThreadedApp.java b/src/main/java/multithread/singlevsmultiplethreads/MultiThreadedApp.java new file mode 100644 index 0000000..981f314 --- /dev/null +++ b/src/main/java/multithread/singlevsmultiplethreads/MultiThreadedApp.java @@ -0,0 +1,62 @@ +package multithread.singlevsmultiplethreads; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +/** + * This folder has two classes which is a good illustration to show the power of multithreading: + * it dramatically improves throughput and speeds up workload! + */ +public class MultiThreadedApp { + private static final int THREAD_POOL_SIZE = 5; + private static final int TOTAL_TASKS = 10; + private static final int MILLISECONDS_TO_FINISH_A_TASK = 1000; + + public static void main(String[] args) throws ExecutionException, InterruptedException { + + long start = System.currentTimeMillis(); + ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE); + List futures = new ArrayList<>(); + for (int i = 0; i < TOTAL_TASKS; i++) { + Runnable worker = new Worker("Worker" + i); + Future future = executorService.submit(worker); + futures.add(future); + } + executorService.shutdown(); + while (!executorService.isTerminated()) { + } + long end = System.currentTimeMillis(); + System.out.println("Multi-threaded app finished, it took " + (end - start) / 1000 + + " seconds for a thread pool of size " + THREAD_POOL_SIZE + " to finish " + + TOTAL_TASKS + " tasks, with each task takes " + MILLISECONDS_TO_FINISH_A_TASK / 1000 + " seconds."); + executorService.shutdown(); + } + + static class Worker implements Runnable { + private String workerName; + + public Worker(String workerName) { + this.workerName = workerName; + } + + @Override + public void run() { + System.out.println(Thread.currentThread().getName() + " starting worker: " + workerName); + doWork(); + System.out.println(Thread.currentThread().getName() + " ended for worker: " + workerName); + } + + private void doWork() { + try { + Thread.sleep(MILLISECONDS_TO_FINISH_A_TASK); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + +} diff --git a/src/main/java/multithread/singlevsmultiplethreads/SingleThreadedApp.java b/src/main/java/multithread/singlevsmultiplethreads/SingleThreadedApp.java new file mode 100644 index 0000000..189f575 --- /dev/null +++ b/src/main/java/multithread/singlevsmultiplethreads/SingleThreadedApp.java @@ -0,0 +1,31 @@ +package multithread.singlevsmultiplethreads; + +public class SingleThreadedApp { + + private static final int TOTAL_TASKS = 10; + private static final int MILLISECONDS_TO_FINISH_A_TASK = 1000; + + public static void main(String[] args) throws InterruptedException { + long start = System.currentTimeMillis(); + work(TOTAL_TASKS); + long end = System.currentTimeMillis(); + System.out.println("Single-threaded app took " + (end - start) / 1000 + + " seconds to finish a total of " + TOTAL_TASKS + + " tasks, with each task takes " + MILLISECONDS_TO_FINISH_A_TASK / 1000 + " seconds."); + } + + private static void work(int n) { + for (int i = 0; i < n; i++) { + doWork(i); + } + } + + private static void doWork(int workNumber) { + System.out.println("Task " + workNumber + " is being worked on."); + try { + Thread.sleep(MILLISECONDS_TO_FINISH_A_TASK); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/sporadic/thread/synchronization/withSynchronization/TestThread.java b/src/main/java/multithread/synchronization/withSynchronization/TestThread.java similarity index 70% rename from src/sporadic/thread/synchronization/withSynchronization/TestThread.java rename to src/main/java/multithread/synchronization/withSynchronization/TestThread.java index cb81460..e027730 100644 --- a/src/sporadic/thread/synchronization/withSynchronization/TestThread.java +++ b/src/main/java/multithread/synchronization/withSynchronization/TestThread.java @@ -1,7 +1,7 @@ /** * */ -package sporadic.thread.synchronization.withSynchronization; +package multithread.synchronization.withSynchronization; /** * This produces the SAME result every time you run this program, in contrast to @@ -12,8 +12,8 @@ * When we start two or more threads within a program, there may be a situation * when multiple threads try to access the same resource and finally they can * produce unforeseen result due to concurrency issue. For example if multiple - * threads try to write within a same file then they may corrupt the data - * because one of the threads can overrite data or while one thread is opening + * threads try to write within the same file then they may corrupt the data + * because one of the threads can overwrite data or while one thread is opening * the same file at the same time another thread might be closing the same file. * * So there is a need to synchronize the action of multiple threads and make @@ -27,11 +27,11 @@ * resources within this block. Following is the general form of the * synchronized statement: * - * synchronized(objectidentifier) { + * synchronized(objectIdentifier) { * // Access shared variables and other shared resources * } * - * Here, the objectidentifier is a reference to an object whose lock associates + * Here, the objectIdentifier is a reference to an object whose lock associates * with the monitor that the synchronized statement represents. Now we are going * to see two examples where we will print a counter using two different * threads. When threads are not synchronized, they print counter value which is @@ -40,19 +40,18 @@ */ public class TestThread { public static void main(String args[]) { + PrintDemo printDemo = new PrintDemo(); - PrintDemo PD = new PrintDemo(); + ThreadDemo threadOne = new ThreadDemo("Thread - 1 ", printDemo); + ThreadDemo threadTwo = new ThreadDemo("Thread - 2 ", printDemo); - ThreadDemo T1 = new ThreadDemo("Thread - 1 ", PD); - ThreadDemo T2 = new ThreadDemo("Thread - 2 ", PD); - - T1.start(); - T2.start(); + threadOne.start(); + threadTwo.start(); // wait for threads to end try { - T1.join(); - T2.join(); + threadOne.join(); + threadTwo.join(); } catch (Exception e) { System.out.println("Interrupted"); } @@ -62,29 +61,30 @@ public static void main(String args[]) { class PrintDemo { public void printCount() { try { + System.out.println(Thread.currentThread().getName() + " is working now.."); for (int i = 5; i > 0; i--) { - System.out.println("Counter --- " + i); + System.out.println("Counter --- " + i + " from thread: " + Thread.currentThread().getName()); } } catch (Exception e) { System.out.println("Thread interrupted."); } } - } class ThreadDemo extends Thread { private Thread t; private String threadName; - PrintDemo PD; + PrintDemo printDemo; ThreadDemo(String name, PrintDemo pd) { threadName = name; - PD = pd; + printDemo = pd; } public void run() { - synchronized (PD) {//Here's all the difference between the two examples! It uses this synchronized keyword to identify the resources that need to be synchronized! - PD.printCount(); + //Here's all the difference between the two examples! It uses this synchronized keyword to identify the resources that need to be synchronized! + synchronized (printDemo) { + printDemo.printCount(); } System.out.println("Thread " + threadName + " exiting."); } diff --git a/src/main/java/multithread/synchronization/withoutSynchronization/TestThread.java b/src/main/java/multithread/synchronization/withoutSynchronization/TestThread.java new file mode 100644 index 0000000..4d00263 --- /dev/null +++ b/src/main/java/multithread/synchronization/withoutSynchronization/TestThread.java @@ -0,0 +1,67 @@ +package multithread.synchronization.withoutSynchronization; + +/** + * This produces DIFFERENT result every time you run this program, in contrast to the one with synchronization. + * Here is a simple example which may or may not print counter value in sequence and every time we run it, it produces different result based on CPU availability to a thread. + * Copied from this link: http://www.tutorialspoint.com/java/java_thread_synchronization.htm, refer to this link for further info. + */ +public class TestThread { + public static void main(String args[]) { + + PrintDemo PD = new PrintDemo(); + + ThreadDemo T1 = new ThreadDemo("Thread - 1 ", PD); + ThreadDemo T2 = new ThreadDemo("Thread - 2 ", PD); + + T1.start(); + T2.start(); + + // wait for threads to end + try { + T1.join(); + T2.join(); + } catch (Exception e) { + System.out.println("Interrupted"); + } + } + +} + + +class PrintDemo { + public void printCount() { + try { + for (int i = 5; i > 0; i--) { + System.out.println("Counter --- " + i); + } + } catch (Exception e) { + System.out.println("Thread interrupted."); + } + } + +} + +class ThreadDemo extends Thread { + private Thread t; + private String threadName; + PrintDemo PD; + + ThreadDemo(String name, PrintDemo pd) { + threadName = name; + PD = pd; + } + + public void run() { + PD.printCount(); + System.out.println("Thread " + threadName + " exiting."); + } + + public void start() { + System.out.println("Starting " + threadName); + if (t == null) { + t = new Thread(this, threadName); + t.start(); + } + } + +} diff --git a/src/main/java/object_mapper_example/ObjectMapperExample.java b/src/main/java/object_mapper_example/ObjectMapperExample.java new file mode 100644 index 0000000..bcbc344 --- /dev/null +++ b/src/main/java/object_mapper_example/ObjectMapperExample.java @@ -0,0 +1,73 @@ +package object_mapper_example; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; + +import static org.junit.Assert.assertNotNull; + +public class ObjectMapperExample { + public static void main(String... args) throws IOException { + System.out.println("Hello world!"); + String str = "{\n" + + " \"Records\": [\n" + + " {\n" + + " \"eventVersion\": \"2.1\",\n" + + " \"eventSource\": \"aws:s3\",\n" + + " \"awsRegion\": \"us-east-1\",\n" + + " \"eventTime\": \"2019-09-10T23:02:48.052Z\",\n" + + " \"eventName\": \"ObjectCreated:Put\",\n" + + " \"userIdentity\": {\n" + + " \"principalId\": \"AWS:SOMETHING_COOL:i-1234\"\n" + + " },\n" + + " \"requestParameters\": {\n" + + " \"sourceIPAddress\": \"12.34.56.78\"\n" + + " },\n" + + " \"responseElements\": {\n" + + " \"x-amz-request-id\": \"SUPER_COOL_ID\",\n" + + " \"x-amz-id-2\": \"SOMETHING_AWESOME_CTU=\"\n" + + " },\n" + + " \"s3\": {\n" + + " \"s3SchemaVersion\": \"1.0\",\n" + + " \"configurationId\": \"QuarantineListAvailableSNS\",\n" + + " \"bucket\": {\n" + + " \"name\": \"staging-data-pact\",\n" + + " \"ownerIdentity\": {\n" + + " \"principalId\": \"WAS_IST_ES\"\n" + + " },\n" + + " \"arn\": \"arn:aws:s3:::staging-data-pact\"\n" + + " },\n" + + " \"object\": {\n" + + " \"key\": \"quarantined_classes/quar_out_2019-09-10-22-00-00.csv\",\n" + + " \"size\": 455211,\n" + + " \"eTag\": \"b39e0617b483c86500ec5319e0951d07\",\n" + + " \"sequencer\": \"005D782B97CD61A2EC\"\n" + + " }\n" + + " }\n" + + " }\n" + + " ]\n" + + "}"; + ObjectMapper mapper = new ObjectMapper(); + JsonNode treeObject = mapper.readTree(str); + assertNotNull(treeObject); + JsonNode records = treeObject.get("Records"); + System.out.println("records: " + records); + + JsonNode s3 = records.get(0); + System.out.println("s3: " + s3); + + JsonNode value = s3.get("s3"); + System.out.println("value: " + value); + + JsonNode object = value.get("object"); + System.out.println("object: " + object); + + String bucket = value.get("bucket").get("name").toString(); + System.out.println("bucket: " + bucket); + + String key = object.get("key").toString(); + System.out.println("key: " + key); + + } +} diff --git a/src/sporadic/producer_consumer_example/ProducerConsumerInJava.java b/src/main/java/producer_consumer_example/ProducerConsumerInJava.java similarity index 98% rename from src/sporadic/producer_consumer_example/ProducerConsumerInJava.java rename to src/main/java/producer_consumer_example/ProducerConsumerInJava.java index c9cc3f4..fec4209 100644 --- a/src/sporadic/producer_consumer_example/ProducerConsumerInJava.java +++ b/src/main/java/producer_consumer_example/ProducerConsumerInJava.java @@ -1,7 +1,4 @@ -/** - * - */ -package sporadic.producer_consumer_example; +package producer_consumer_example; import java.util.LinkedList; import java.util.Queue; diff --git a/src/main/java/profiler/IntellijProfilerExample.java b/src/main/java/profiler/IntellijProfilerExample.java new file mode 100644 index 0000000..1077a30 --- /dev/null +++ b/src/main/java/profiler/IntellijProfilerExample.java @@ -0,0 +1,51 @@ +package profiler; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Deque; +import java.util.concurrent.TimeUnit; + +public class IntellijProfilerExample { + /**Source: https://github.com/flounder4130/profiler-example/tree/master*/ + public static int update(Deque events, long nanos, long interval) { + events.add(nanos); + events.removeIf(aTime -> aTime < nanos - interval); + /* + //noinspection ConstantConditions + while (events.peekFirst() < nanos - interval) { + events.removeFirst(); + } + */ + return events.size(); + } + + public static void main(String[] args) throws IOException { + System.out.println("Program started."); + long start = System.nanoTime(); + int total = 100_000; + long interval = TimeUnit.MILLISECONDS.toNanos(100); + int[] count = new int[total]; + + Deque collection = new ArrayDeque<>(); + for (int counter = 0; counter < count.length; counter++) { + count[counter] = update(collection, System.nanoTime(), interval); + Path p = Paths.get("./a/b"); + Files.createDirectories(p); + /* + if (!Files.exists(p)) { + Files.createDirectories(p); + } + */ + } + long spent = System.nanoTime() - start; + + //noinspection OptionalGetWithoutIsPresent + System.out.println("Average count: " + (int) (Arrays.stream(count).average().getAsDouble()) + " op"); + System.out.println("Spent time: " + TimeUnit.NANOSECONDS.toMillis(spent) + " ms"); + System.out.println("\nProgram finished."); + } +} diff --git a/src/main/java/profiler/SimpleProfiler.java b/src/main/java/profiler/SimpleProfiler.java new file mode 100644 index 0000000..f165b6a --- /dev/null +++ b/src/main/java/profiler/SimpleProfiler.java @@ -0,0 +1,23 @@ +package profiler; + +public class SimpleProfiler { + /** + * From this post: https://stackoverflow.com/a/9415368/4117496 + * To run this: go to terminal and use this command: + * java -server -XX:+UnlockDiagnosticVMOptions '-XX:CompileCommand=print,*Main.main' src/main/java/profiler/Main.java + * but it produces this error: + * Could not load hsdis-aarch64.dylib; library not loadable; PrintAssembly is disabled + * I didn't dig further after this. + * */ + public static void main(final String[] args) { + long x = 0; + for (int i = 0; i < 1000000; i++) { + x += calculate(i); + } + System.out.println("x = " + x); + } + + private static long calculate(final int i) { + return (long) i * (long) i; + } +} diff --git a/src/main/java/randomExamples/ClassInstance.java b/src/main/java/randomExamples/ClassInstance.java new file mode 100644 index 0000000..89fa1c0 --- /dev/null +++ b/src/main/java/randomExamples/ClassInstance.java @@ -0,0 +1,26 @@ +package randomExamples; + +public class ClassInstance { + + public static class A { + int a; + + public A(int a) { + this.a = a; + } + } + + public static void method1(A a) { + a = new A(2); + } + + public static void main(String... args) { + System.out.println("Program started."); + ClassInstance.A a = new ClassInstance.A(9); + System.out.println(a.a);//should print out 9 + method1(new ClassInstance.A(10)); + System.out.println(a.a);//should print out 9 as well because as soon as the function method1's scope exits, the changed object of a within method1 undoes the change. + System.out.println("Program finished."); + } + +} diff --git a/src/main/java/randomExamples/EnumExamples.java b/src/main/java/randomExamples/EnumExamples.java new file mode 100644 index 0000000..3204205 --- /dev/null +++ b/src/main/java/randomExamples/EnumExamples.java @@ -0,0 +1,17 @@ +package randomExamples; + +public class EnumExamples { + public static void main(String... args) { + System.out.println(RequestType.GET); + System.out.println(RequestType.GET == RequestType.GET); + System.out.println(RequestType.GET.name()); + } +} + +enum RequestType { + GET, + PUT, + POST, + PATCH, + DELETE +} diff --git a/src/main/java/randomExamples/OpenCSVExample.java b/src/main/java/randomExamples/OpenCSVExample.java new file mode 100644 index 0000000..6879c1f --- /dev/null +++ b/src/main/java/randomExamples/OpenCSVExample.java @@ -0,0 +1,31 @@ +package randomExamples; + +import com.opencsv.CSVReader; +import com.opencsv.exceptions.CsvValidationException; + +import java.io.FileReader; +import java.io.IOException; + +public class OpenCSVExample { + /** + * This is a good example to show that this popular CSV library that can handle fields that contain comma in CSV files well. + * Look at this file: values_with_comma_inside.csv, some fields have comma in them, which are enclosed with double quotes, + * if you use string.split(","), that field will be broken into parts which is wrong, + * whereas using this library will help take care of this case very well. + */ + public static void main(String[] args) throws CsvValidationException { + String file = "src/test/resources/values_with_comma_inside.csv"; + try (CSVReader reader = new CSVReader(new FileReader(file))) { + String[] nextLine; + while ((nextLine = reader.readNext()) != null) { + System.out.println("nextLine.length is: " + nextLine.length); + for (int i = 0; i < nextLine.length; i++) { + System.out.println("nextLine[" + i + "] is: " + nextLine[i]); + } + System.out.println(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/randomExamples/Size.java b/src/main/java/randomExamples/Size.java new file mode 100644 index 0000000..714580b --- /dev/null +++ b/src/main/java/randomExamples/Size.java @@ -0,0 +1,99 @@ +package randomExamples; + +import java.io.UnsupportedEncodingException; + +public class Size { + public static void main(String... args) throws UnsupportedEncodingException { + System.out.println("Program started."); + System.out.println(Integer.MAX_VALUE);//2,147,483,647 + System.out.println(Integer.MIN_VALUE);//-2,147,483,648 + System.out.println(getByteBits());//8 + System.out.println(getShortBits());//16 + System.out.println(getIntegerBits());//32 + System.out.println(getLongBits());//64 + System.out.println(is64bit0());//check if the machine that this program runs on is 64-bit + System.out.println(Integer.toBinaryString(-1)); + System.out.println(Integer.toBinaryString(-1).length());//32 + System.out.println(Integer.toBinaryString(1).length());//1 + + // The input string for this test + final String string = "Hello World"; + + // Check length, in characters + System.out.println(string.length()); // prints "11" + + // Check encoded sizes + final byte[] utf8Bytes = string.getBytes("UTF-8"); + System.out.println(utf8Bytes.length); // prints "11" + + final byte[] utf16Bytes = string.getBytes("UTF-16"); + System.out.println(utf16Bytes.length); // prints "24" + + final byte[] utf32Bytes = string.getBytes("UTF-32"); + System.out.println(utf32Bytes.length); // prints "44" + + final byte[] isoBytes = string.getBytes("ISO-8859-1"); + System.out.println(isoBytes.length); // prints "11" + + final byte[] winBytes = string.getBytes("CP1252"); + System.out.println(winBytes.length); // prints "11" + + + System.out.println("Program finished."); + } + + private static boolean is64bit0() { + String systemProp = System.getProperty("com.ibm.vm.bitmode"); + if (systemProp != null) { + return "64".equals(systemProp); + } + systemProp = System.getProperty("sun.arch.data.model"); + if (systemProp != null) { + return "64".equals(systemProp); + } + systemProp = System.getProperty("java.vm.version"); + return systemProp != null && systemProp.contains("_64"); + } + + public static int getByteBits() { + int i = 1; + byte j = 1; + for (; (j = (byte) (j << 1)) > 0; i++) { + } + //Compensation of the sign bit 1 + return i + 1; + } + + public static int getShortBits() { + int i = 1; + short j = 1; + + for (; (j = (short) (j << 1)) > 0; i++) + ; + + //Compensation of the sign bit 1 + return i + 1; + } + + public static int getIntegerBits() { + int i = 1; + int j = 1; + + for (; (j = j << 1) > 0; i++) + ; + + //Compensation of the sign bit 1 + return i + 1; + } + + public static int getLongBits() { + int i = 1; + long j = 1; + + for (; (j = j << 1) > 0; i++) + ; + + //Compensation of the sign bit 1 + return i + 1; + } +} diff --git a/src/main/java/semaphore/ConnectionLimiter.java b/src/main/java/semaphore/ConnectionLimiter.java new file mode 100644 index 0000000..751154e --- /dev/null +++ b/src/main/java/semaphore/ConnectionLimiter.java @@ -0,0 +1,70 @@ +package semaphore; + +import java.util.concurrent.Semaphore; + +/** + * This is a small program to demo how semaphore can create trouble for us. + * One rule of thumb is: + * Always release what you acquire! + * Copied from the Internet. + */ +//this is a bad public class name, it doesn't apply to +//what this class really do, it's a name from a different class that I copied earlier. +public class ConnectionLimiter { + + private static class DoubleResourceGrabber implements Runnable { + + private Semaphore first; + private Semaphore second; + + public DoubleResourceGrabber(Semaphore s1, Semaphore s2) { + first = s1; + second = s2; + } + + @Override + public void run() { + Thread t = Thread.currentThread(); + + try { + first.acquire(); + System.out.println(t.getName() + " acquired " + first); + +// Thread.sleep(20);//to demo a deadlock + +// second.acquire(); +// System.out.println(t.getName() + " acquired " + second); + +// second.release(); +// System.out.println(t.getName() + " released " + second); + + first.release(); + System.out.println(t.getName() + " released " + first); + + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + /** + * @param args + * @throws InterruptedException + */ + public static void main(String[] args) throws InterruptedException { + Semaphore s1 = new Semaphore(1);//give it only 1 permit + Semaphore s2 = new Semaphore(1);//give it only 1 permit as well + Thread t1 = new Thread(new DoubleResourceGrabber(s1, s2)); + //now reverse them, here comes the trouble + Thread t2 = new Thread(new DoubleResourceGrabber(s2, s1)); + + t1.start(); + t2.start(); + + t1.join(); + t2.join(); + System.out.println("We got lucky!"); + + } + +} diff --git a/src/sporadic/socket_programming/GreetingClient.java b/src/main/java/socket_programming/GreetingClient.java similarity index 96% rename from src/sporadic/socket_programming/GreetingClient.java rename to src/main/java/socket_programming/GreetingClient.java index 852dabf..ee2760b 100644 --- a/src/sporadic/socket_programming/GreetingClient.java +++ b/src/main/java/socket_programming/GreetingClient.java @@ -1,4 +1,4 @@ -package sporadic.socket_programming; +package socket_programming; import java.io.DataInputStream; import java.io.DataOutputStream; diff --git a/src/sporadic/socket_programming/GreetingServer.java b/src/main/java/socket_programming/GreetingServer.java similarity index 98% rename from src/sporadic/socket_programming/GreetingServer.java rename to src/main/java/socket_programming/GreetingServer.java index 49dc5e2..8501c86 100644 --- a/src/sporadic/socket_programming/GreetingServer.java +++ b/src/main/java/socket_programming/GreetingServer.java @@ -1,4 +1,4 @@ -package sporadic.socket_programming; +package socket_programming; import java.io.DataInputStream; import java.io.DataOutputStream; diff --git a/src/main/java/sorting/HeapSort.java b/src/main/java/sorting/HeapSort.java new file mode 100644 index 0000000..1e493af --- /dev/null +++ b/src/main/java/sorting/HeapSort.java @@ -0,0 +1,74 @@ +package sorting; + +public class HeapSort { + private static int N; + + public static void sort(int[] nums) { + heapify(nums);// put the initial array into a heap + for (int i = N; i > 0; i--) { + swap(nums, 0, i);// the number at index zero is always the largest + // in + // the current UN-sorted array, so we always swap it with the + // current + // last one which is i + N = N - 1;// then we decrement N by 1 so that in the following + // maxheap() function we only need to work on elements + // from index zero to N (this N is decremented by 1 each + // time) + maxheap(nums, 0);// this is the maintain the heap property after + // placing its previous largest number into the + // correct place and get ready for next round of + // swap: take the max (root) out from the heap. + } + } + + //this function is used to maintain the heap, always re-position the number at index i to its correct place + private static void maxheap(int[] nums, int i) { + int left = 2*i; + int right = left+1; + int max = i; + if(left <= N && nums[left] > nums[i]){ + max = left; + } + if(right <= N && nums[right] > nums[max]){ + max = right; + } + + if(max != i){ + swap(nums, i, max); + maxheap(nums, max); + } + } + + private static void heapify(int[] nums) { + N = nums.length-1; + for(int i = N/2; i >= 0; i--){ + maxheap(nums, i); + } + } + + private static void swap(int[] nums, int i, int j) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } + + public static void main(String...strings){ + int[] nums = new int[]{6,5,3,1,8,7,2,4}; + // int[] nums = new int[]{1,2,3,4,5,6}; + // int[] nums = new int[]{6,5,4,3,2,1}; +// int[] nums = new int[]{488, 667, 634, 380, 944, 594, 783, 584, 550, 665, 721, 819, 285, 344, 503, 807, 491, 623, 845, 300}; + print("BEFORE printing, nums are: ", nums); + sort(nums); + print("AFTER printing, nums are: ", nums); + System.out.println(); + } + + private static void print(String msg, int[] nums) { + System.out.println(msg); + for(int i : nums){ + System.out.print(i + ", "); + } + System.out.println(); + } +} diff --git a/src/main/java/sorting/HeapSortAgain.java b/src/main/java/sorting/HeapSortAgain.java new file mode 100644 index 0000000..272b97b --- /dev/null +++ b/src/main/java/sorting/HeapSortAgain.java @@ -0,0 +1,58 @@ +package sorting; + +/**After completing understanding this algorithm, I implemented myself, so this class is called HeapSortAgain.*/ +public class HeapSortAgain { + private static int N; + public static void sort(int[] nums){ + heapify(nums); + for(int i = N; i > 0; i--){//i doesn't need to be equal to zero, because we don't need to swap zero-indexed number with itself + swap(nums, i, 0);//we always swap the first element in the array which means it's at the root of the heap with the number at index i which is the largest index in the UN-sorted array + N -= 1;//don't remember to decrement N by 1, because we only need to worry about one number fewer each time + maxheap(nums, 0);//then we always update the heap for the number at index zero + } + } + private static void heapify(int[] nums) { + N = nums.length-1; + for(int i = N/2; i >= 0; i--){//here we need i to be equal to zero because we need to do maxheap() on its first element as well + maxheap(nums, i); + } + } + private static void maxheap(int[] nums, int i) { + int leftChildIndex = 2*i; + int rightChildIndex = leftChildIndex+1; + int max = i; + if(leftChildIndex <= N && nums[leftChildIndex] > nums[i]){ + max = leftChildIndex; + } + if(rightChildIndex <= N && nums[rightChildIndex] > nums[max]){ + max = rightChildIndex; + } + if(i != max){ + swap(nums, i, max); + maxheap(nums, max); + } + } + private static void swap(int[] nums, int i, int j) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } + public static void main(String...strings){ + int[] nums = new int[]{6,5,3,1,8,7,2,4}; + // int[] nums = new int[]{1,2,3,4,5,6}; + // int[] nums = new int[]{6,5,4,3,2,1}; +// int[] nums = new int[]{488, 667, 634, 380, 944, 594, 783, 584, 550, 665, 721, 819, 285, 344, 503, 807, 491, 623, 845, 300}; + print("BEFORE printing, nums are: ", nums); + sort(nums); + print("AFTER printing, nums are: ", nums); + System.out.println(); + } + + private static void print(String msg, int[] nums) { + System.out.println(msg); + for(int i : nums){ + System.out.print(i + ", "); + } + System.out.println(); + } +} diff --git a/src/main/java/sorting/InsertionSort.java b/src/main/java/sorting/InsertionSort.java new file mode 100644 index 0000000..31409a7 --- /dev/null +++ b/src/main/java/sorting/InsertionSort.java @@ -0,0 +1,61 @@ +package sorting; + +import java.util.Random; + +public class InsertionSort { + + public static int[] generateRandomArray(int len) { + int[] nums = new int[len]; + for(int i = 0; i < len; i++){ + nums[i] = (new Random()).nextInt(200); + } + return nums; + } + + public int[] insertionSort(int[] nums){ + long lStartTime = System.currentTimeMillis(); + for(int i = 1; i < nums.length; i++){ + int j = i-1; + if(nums[i] > nums[j]) continue; + while(j >= 0 && nums[j] > nums[i]){ + swap(nums, j, i); + j--; + i--; + } + } + long lEndTime = System.currentTimeMillis(); + System.out.println("Elapsed milliseconds: " + (lEndTime - lStartTime)); + return nums; + } + + private void swap(int[] nums, int j, int i) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } + + public static void main(String... args){ +// System.out.println(2 >> 4); +// System.out.println(Integer.toBinaryString(32)); + int[] nums = generateRandomArray(10); + InsertionSort test = new InsertionSort(); + SortUtils.print(nums); +// test.swap(nums, 2, 0); +// test.print(nums); + SortUtils.print(test.insertionSortAgain(nums)); +// test.print(test.insertionSort(nums)); + } + + public int[] insertionSortAgain(int[] nums){ + for(int i = 1; i < nums.length; i++){ + for(int j = i-1; j >= 0; j--){ + if(nums[j+1] <= nums[j]){ + int temp = nums[j+1]; + nums[j+1] = nums[j]; + nums[j] = temp; + } + } + } + return nums; + } +} diff --git a/src/main/java/sorting/MergeSort.java b/src/main/java/sorting/MergeSort.java new file mode 100644 index 0000000..b39b5ad --- /dev/null +++ b/src/main/java/sorting/MergeSort.java @@ -0,0 +1,69 @@ +package sorting; + +public class MergeSort { + public static void main(String... strings) { + int a[] = new int[]{9, 3, 8, 6, 2, 1, 5, 4}; + int b[] = new int[a.length]; + + System.out.println("List before sorting\n"); + for (int i = 0; i < a.length; i++) System.out.print(a[i] + " "); + + MergeSort test = new MergeSort(); + test.sort(a, 0, a.length - 1); + + System.out.println("\nList after sorting\n"); + for (int i = 0; i < a.length; i++) System.out.print(a[i] + " "); + } + + public void sort(int[] arr, int l, int r) { + if (l < r) { + int m = (l + r) / 2; + sort(arr, l, m); + sort(arr, m + 1, r); + merge(arr, l, m, r); + } + } + + private void merge(int[] arr, int l, int m, int r) { + //find sizes of two subarrays that are to be merged + int size1 = m - l + 1; + int size2 = r - m; + + //copy the two subarrays into two temp arrays + int[] tempL = new int[size1]; + int[] tempR = new int[size2]; + for (int i = 0; i < size1; i++) { + tempL[i] = arr[l + i]; + } + for (int i = 0; i < size2; i++) { + tempR[i] = arr[m + i + 1]; + } + + //now we merge the two subarrays + + //initial indices of the two subarrays + int i = 0, j = 0; + + //initial index of the merged subarray array + int k = l; + + while (i < size1 && j < size2) { + if (tempL[i] <= tempR[j]) { + arr[k] = tempL[i]; + i++; + } else { + arr[k] = tempR[j]; + j++; + } + k++; + } + + //copy remaining list into arr if any + while (i < size1) { + arr[k++] = tempL[i++]; + } + while (j < size2) { + arr[k++] = tempR[j++]; + } + } +} diff --git a/src/main/java/sorting/QuickSort.java b/src/main/java/sorting/QuickSort.java new file mode 100644 index 0000000..4b132c8 --- /dev/null +++ b/src/main/java/sorting/QuickSort.java @@ -0,0 +1,198 @@ +package sorting; + +public class QuickSort { + + public static class QuickSortPartitionLast { + public int[] quickSort(int[] nums) { + quickSort(nums, 0, nums.length - 1); + return nums; + } + + private void quickSort(int[] nums, int low, int high) { + if (low < high) { + int pi = partitionLast(nums, low, high); + quickSort(nums, low, pi - 1); + quickSort(nums, pi + 1, high); + } + + } + + private int partitionLast(int[] nums, int low, int high) { + int pivot = nums[high]; + int i = (low - 1); + for (int j = low; j <= high - 1; j++) { + if (nums[j] <= pivot) { + i++; + //swap nums[i] and nums[j] + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } + } + + //swap nums[i+1] and nums[high] + int temp = nums[i + 1]; + nums[i + 1] = nums[high]; + nums[high] = temp; + + return i + 1; + } + } + + public static class QuickSortPartitionFirst { + public int[] quickSort(int[] nums) { + quickSort(nums, 0, nums.length - 1); + return nums; + } + + private void quickSort(int[] nums, int low, int high) { + if (low < high) { + int pi = partitionFirst(nums, low, high); + quickSort(nums, low, pi - 1); + quickSort(nums, pi + 1, high); + } + + } + + // this method find the pivot and do the sorting + private int partitionFirst(int[] list, int first, int last) { + int pivot = list[first]; + int low = first + 1; // searching forward from pivot'next element + int high = last;// searching from the end for backward + while (low < high) { + // forward searching + while (low <= high && list[low] < pivot) + low++; + // backward searching + while (low <= high && list[high] >= pivot) + high--; + // swap two elements in the list when list[high] low) { + int temp = list[high]; + list[high] = list[low]; + list[low] = temp; + } + } + + while (high > first && list[high] >= pivot) + high--; + // swap pivot + if (pivot > list[high]) { + list[first] = list[high]; + list[high] = pivot; + return high; + } else { + return first; + } + } + } + + public static void main(String... args){ + int[] nums = InsertionSort.generateRandomArray(17); +// int[] nums = new int[]{10, 7, 8, 9, 1, 5}; + SortUtils.print(nums); +// test.swap(nums, 2, 0); +// test.print(nums); + QuickSort test = new QuickSort(); +// InsertionSort.print(test.quickSort(nums)); +// InsertionSort.print(test.quickSort_20160628(nums)); +// InsertionSort.print(test.quickSort_pivot_first_20160628(nums)); + SortUtils.print(test.quickSort_pivot_median_20160628(nums)); + + + } + + int[] quickSort_20160628(int[] nums){ + quickSort_20160628(nums, 0, nums.length-1); + return nums; + } + + void quickSort_20160628(int[] nums, int low, int high) { + if(low < high){ + int pi = partition_20160628(nums, low, high); + quickSort_20160628(nums, low, pi-1); + quickSort_20160628(nums, pi+1, high); + } + } + + int partition_20160628(int[] nums, int low, int high) { + int pivot = nums[high]; + int i = low-1; + for(int j = low; j <= high-1; j++){ + if(nums[j] <= pivot){ + i++; + + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } + } + + int temp = nums[i+1]; + nums[i+1] = nums[high]; + nums[high] = temp; + return i+1; + } + + //This below method is also accepted on http://www.practice.geeksforgeeks.org/problem-page.php?pid=700151 + int[] quickSort_pivot_first_20160628(int[] nums){ + quickSort_pivot_first_20160628(nums, 0, nums.length-1); + return nums; + } + + private void quickSort_pivot_first_20160628(int[] nums, int low, int high) { + if (low < high) { + int pi = partition_pivot_first_20160628(nums, low, high); + quickSort_pivot_first_20160628(nums, low, pi - 1); + quickSort_pivot_first_20160628(nums, pi + 1, high); + } + } + + private int partition_pivot_first_20160628(int[] nums, int low, int high) { + int pivot = nums[low]; + int i = high+1; + for(int j = high; j > low; j--){ + if(nums[j] > pivot){ + i--; + + int temp = nums[j]; + nums[j] = nums[i]; + nums[i] = temp; + } + } + + int temp = nums[low]; + nums[low] = nums[i-1]; + nums[i-1] = temp; + + return i-1; + } + + int[] quickSort_pivot_median_20160628(int[] nums){ + quickSort_pivot_median_20160628(nums, 0, nums.length-1); + return nums; + } + + void quickSort_pivot_median_20160628(int[] nums, int low, int high) { + if(nums == null || nums.length == 0) return ; + if(low >= high) return; + + int i = low, j = high, mid = (low+high)/2, pivot = nums[mid]; + + while(i <= j){ + while(nums[i] < pivot) i++; + while(nums[j] > pivot) j--; + if(i <= j){ + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + i++; + j--; + } + } + + if(low < j) quickSort_pivot_median_20160628(nums, low, j); + if(i < high) quickSort_pivot_median_20160628(nums, i, high); + } + +} diff --git a/src/main/java/sorting/RadixSort.java b/src/main/java/sorting/RadixSort.java new file mode 100644 index 0000000..9f8ee91 --- /dev/null +++ b/src/main/java/sorting/RadixSort.java @@ -0,0 +1,7 @@ +package sorting; + +/** + * Created by stevesun on 2/18/17. + */ +public class RadixSort { +} diff --git a/src/main/java/sorting/SortUtils.java b/src/main/java/sorting/SortUtils.java new file mode 100644 index 0000000..6572e2f --- /dev/null +++ b/src/main/java/sorting/SortUtils.java @@ -0,0 +1,11 @@ +package sorting; + +/** + * Created by stevesun on 8/14/17. + */ +public class SortUtils { + public static void print(int[] nums){ + for(int i : nums) System.out.print( i + ", "); + System.out.println(); + } +} diff --git a/src/main/java/sparkExamples/Input1.txt b/src/main/java/sparkExamples/Input1.txt new file mode 100644 index 0000000..e490523 --- /dev/null +++ b/src/main/java/sparkExamples/Input1.txt @@ -0,0 +1,5 @@ +A wonderful king is Hadoop. - Ada +The elephant plays well with Sqoop. - Rachel +But what helps him to thrive - Ada +Are Impala, and Hive, - Rachel +And HDFS in the group. - Ada \ No newline at end of file diff --git a/src/main/java/sparkExamples/JavaParquetExample1.java b/src/main/java/sparkExamples/JavaParquetExample1.java new file mode 100644 index 0000000..f2f5da0 --- /dev/null +++ b/src/main/java/sparkExamples/JavaParquetExample1.java @@ -0,0 +1,49 @@ +package sparkExamples; + +import org.apache.spark.api.java.JavaRDD; +import org.apache.spark.sql.Dataset; +import org.apache.spark.sql.Row; +import org.apache.spark.sql.SparkSession; + +import java.util.Arrays; +import java.util.regex.Pattern; + +public class JavaParquetExample1 { + /** + * How to run this program: + * 1. locally: mvn package && mvn exec:java -Dexec.mainClass=sparkExamples.SparkExample1 -Dexec.args="sparkExamples/Input1.txt sparkExamples/Output1.txt" + * 2. on AWS EMR cluster: + * mvn package + * upload the compiled jar file: RandomJava-1.0-SNAPSHOT.jar to an S3 bucket + * click add steps to a ready cluster on AWS EMR + * --class sparkExamples.JavaParquetExample1 + * specify the jar in your S3 location + * --s3://sunstev-test/your-file.parquet (in your arguments section) + */ + + private static final Pattern SPACE = Pattern.compile(" "); + + public static void main(String[] args) { + System.out.println("Hello world!"); + System.out.println("args.length:" + args.length); + if (args.length > 0) { + Arrays.stream(args).map(arg -> "arg: " + arg).forEach(System.out::println); + } + try { + SparkSession spark = SparkSession + .builder() + .appName("SparkJob") + .config("spark.eventLog.enabled", "true") +// .config("spark.master", "local")//keep this one commented out if you want to run in cluster mode + .getOrCreate(); + System.out.println("SparkSession is initated."); + + Dataset parquetFileDF = spark.read().parquet(args[0]); + JavaRDD rdd = parquetFileDF.toJavaRDD(); + rdd.saveAsTextFile(args[1]); + } catch (Exception e) { + System.out.println("Caught exception when processing: " + e); + } + + } +} diff --git a/src/main/java/sparkExamples/JavaSparkPi.java b/src/main/java/sparkExamples/JavaSparkPi.java new file mode 100644 index 0000000..f634fe4 --- /dev/null +++ b/src/main/java/sparkExamples/JavaSparkPi.java @@ -0,0 +1,64 @@ +package sparkExamples; + +import org.apache.spark.SparkConf; +import org.apache.spark.api.java.JavaRDD; +import org.apache.spark.api.java.JavaSparkContext; +import org.apache.spark.api.java.function.Function; +import org.apache.spark.api.java.function.Function2; + +import java.util.ArrayList; +import java.util.List; + +/** + * Computes an approximation to pi + * Usage: JavaSparkPi [slices] + * + * NOTE: it's throwing Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 28499 when running locally through Intellij. + * But it runs fine on AWS EMR, here's how to run it on AWS EMR: + * mvn package + * upload the compiled jar file: RandomJava-1.0-SNAPSHOT.jar to an S3 bucket + * click add steps to a ready cluster on AWS EMR + * --class sparkExamples.JavaSparkPi + * specify the jar in your S3 location + */ +public final class JavaSparkPi { + + public static void main(String[] args) throws Exception { + SparkConf sparkConf = new SparkConf() + .setAppName("JavaSparkPi") +// .setMaster("local")//uncomment this if you run it on AWS EMR in cluster mode + ; + JavaSparkContext jsc = new JavaSparkContext(sparkConf); + System.out.println("JavaSparkContext is initiated."); + + int slices = (args.length == 1) ? Integer.parseInt(args[0]) : 2; + int n = 1000 * slices; + List list = new ArrayList<>(n); + for (int i = 0; i < n; i++) { + list.add(i); + } + System.out.println("Got list.size() is: " + list.size()); + + JavaRDD dataSet = jsc.parallelize(list, slices); + System.out.println("dataSet.count() is: " + dataSet.count()); + + int count = dataSet.map(new Function() { + @Override + public Integer call(Integer integer) { + double x = Math.random() * 2 - 1; + double y = Math.random() * 2 - 1; + return (x * x + y * y < 1) ? 1 : 0; + } + }).reduce(new Function2() { + @Override + public Integer call(Integer integer, Integer integer2) { + return integer + integer2; + } + }); + + System.out.println("Pi is roughly " + 4.0 * count / n); + + jsc.stop(); + } +} + diff --git a/src/main/java/sparkExamples/SparkExample1.java b/src/main/java/sparkExamples/SparkExample1.java new file mode 100644 index 0000000..c6f8a80 --- /dev/null +++ b/src/main/java/sparkExamples/SparkExample1.java @@ -0,0 +1,57 @@ +package sparkExamples; + +import org.apache.spark.api.java.JavaPairRDD; +import org.apache.spark.api.java.JavaRDD; +import org.apache.spark.sql.SparkSession; +import scala.Tuple2; + +import java.util.Arrays; +import java.util.regex.Pattern; + +public class SparkExample1 { + /** + * How to run this program: + * 1. locally: mvn package && mvn exec:java -Dexec.mainClass=sparkExamples.SparkExample1 -Dexec.args="sparkExamples/Input1.txt sparkExamples/Output1.txt" + * 2. on AWS EMR cluster: + * mvn package + * upload the compiled jar file: RandomJava-1.0-SNAPSHOT.jar to an S3 bucket + * click add steps to a ready cluster on AWS EMR + * --class sparkExamples.SparkExample1 + * specify the jar in your S3 location + * --s3://sunstev-test/Input1.txt --s3://sunstev-test/Output1.txt (in your arguments section) + */ + + private static final Pattern SPACE = Pattern.compile(" "); + + public static void main(String[] args) { + System.out.println("Hello world!"); + System.out.println("args.length:" + args.length); + if (args.length < 2) { + System.err.println("Usage: JavaWordCount "); + System.exit(1); + } + System.out.println("args.[0]:" + args[0] + ", args[1]: " + args[1]); + try { + SparkSession spark = SparkSession + .builder() + .appName("SparkJob") +// .config("spark.master", "local")//keep this one commented out if you want to run in cluster mode + .getOrCreate(); + System.out.println("SparkSession is initated."); + + JavaRDD textFile = spark.read().textFile(args[0]).toJavaRDD(); + System.out.println("Finished reading this textFile: " + args[0]); + + JavaPairRDD counts = textFile + .flatMap(s -> Arrays.asList(SPACE.split(s)).iterator()) + .mapToPair(s -> new Tuple2<>(s, 1)) + .reduceByKey((a, b) -> a + b); + System.out.println("Finished doing MapReduce option on this textFile: " + args[0]); + + counts.saveAsTextFile(args[1]); + System.out.println("Finished saving output to this textFile: " + args[1]); + } catch (Exception e) { + System.out.println("Caught exception when processing: " + e); + } + } +} diff --git a/src/main/java/sporadic/GeneralizeExample.java b/src/main/java/sporadic/GeneralizeExample.java new file mode 100644 index 0000000..2c87e71 --- /dev/null +++ b/src/main/java/sporadic/GeneralizeExample.java @@ -0,0 +1,104 @@ +package sporadic; + +import java.util.Set; + +/**Posted the question here: + * https://softwareengineering.stackexchange.com/questions/398727/how-to-generalize-this-method-for-its-duplicate-common-logic/398731#398731 + * */ +public class GeneralizeExample { + + /**Apparently the logic in specificMethod is duplicated, how can we generalize them and make it extensible? In case there's SetThree, SetFour in the future that needs to be added to this method?*/ + public void specificMethod(DDBRecord ddbRecord, Set incomingSetOne, Set incomingSetTwo, String incomingString) { + Set existingSetOne = ddbRecord.getSetOne(); + if (existingSetOne == null) { + if (!incomingSetOne.isEmpty()) { + ddbRecord.setSetOne(incomingSetOne); + ddbRecord.setSetOneCount(incomingSetOne.size()); + existingSetOne = incomingSetOne; + } + } else if (existingSetOne != null) { + if (incomingSetOne.isEmpty()) { + //remove this string from this set if it exists + existingSetOne.remove(incomingString); + int updatedSetOneCount = existingSetOne.size(); + ddbRecord.setSetOneCount(updatedSetOneCount); + if (updatedSetOneCount == 0) { + existingSetOne.add("N/A"); + } + ddbRecord.setSetOne(existingSetOne); + } else if (!incomingSetOne.isEmpty()) { + if (existingSetOne.contains("N/A")) { + existingSetOne.remove("N/A"); + } + //add this incoming set in + existingSetOne.addAll(incomingSetOne); + + ddbRecord.setSetOne(existingSetOne); + ddbRecord.setSetOneCount(existingSetOne.size()); + } + } + + Set existingSetTwo = ddbRecord.getSetTwo(); + if (existingSetTwo == null) { + if (!incomingSetTwo.isEmpty()) { + ddbRecord.setSetTwo(incomingSetTwo); + ddbRecord.setSetTwoCount(incomingSetTwo.size()); + existingSetTwo = incomingSetTwo; + } + } else if (existingSetTwo != null) { + if (incomingSetTwo.isEmpty()) { + //remove this string from this set if it exists + existingSetTwo.remove(incomingString); + int updatedSetTwoCount = existingSetTwo.size(); + ddbRecord.setSetTwoCount(updatedSetTwoCount); + if (updatedSetTwoCount == 0) { + existingSetTwo.add("N/A"); + } + ddbRecord.setSetTwo(existingSetTwo); + } else if (!incomingSetTwo.isEmpty()) { + if (existingSetTwo.contains("N/A")) { + existingSetTwo.remove("N/A"); + } + //add this incoming offer set in + existingSetTwo.addAll(incomingSetTwo); + + ddbRecord.setSetTwo(existingSetTwo); + ddbRecord.setSetTwoCount(existingSetTwo.size()); + } + } + + //do something w/ existingSetOne and existingSetTwo afterwards + } + + class DDBRecord { + private Set setOne; + private Set setTwo; + private int setOneCount; + private int setTwoCount; + + public Set getSetOne() { + return setOne; + } + + public void setSetOne(Set setOne) { + this.setOne = setOne; + } + + public void setSetOneCount(int count) { + this.setOneCount = count; + } + + public Set getSetTwo() { + return setTwo; + } + + public void setSetTwo(Set setTwo) { + this.setTwo = setTwo; + } + + public void setSetTwoCount(int count) { + this.setTwoCount = count; + } + } + +} diff --git a/src/sporadic/ProgramToFindMachineInfo.java b/src/main/java/sporadic/ProgramToFindMachineInfo.java similarity index 100% rename from src/sporadic/ProgramToFindMachineInfo.java rename to src/main/java/sporadic/ProgramToFindMachineInfo.java diff --git a/src/main/java/sporadic/RegexTestPatternMatcher.java b/src/main/java/sporadic/RegexTestPatternMatcher.java new file mode 100644 index 0000000..673bc74 --- /dev/null +++ b/src/main/java/sporadic/RegexTestPatternMatcher.java @@ -0,0 +1,41 @@ +package sporadic; + +/** + * Created by stevesun on 1/22/17. + */ + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/**This is a program to play around with regex, I asked a question on SO: http://stackoverflow.com/questions/41774435/how-to-split-a-string-based-on-in-java*/ +public class RegexTestPatternMatcher { + public static final String EXAMPLE_TEST = "This is my small example string which I'm going to use for pattern matching."; + + public static void main(String[] args) { + String string = "[{1000, 500, 1}, {1001, 501, 1}, {1002, 501, 2}]"; + Matcher m = Pattern.compile("\\{[0-9, ]+\\}").matcher(string); + while(m.find()){ + System.out.println(m.group()); + } + + Pattern pattern = Pattern.compile("\\w+"); + // in case you would like to ignore case sensitivity, + // you could use this statement: + // Pattern pattern = Pattern.compile("\\s+", Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(EXAMPLE_TEST); + // check all occurance + while (matcher.find()) { + System.out.print("Start index: " + matcher.start()); + System.out.print(" End index: " + matcher.end() + " "); + System.out.println(matcher.group()); + } + // now create a new pattern and matcher to replace whitespace with tabs + Pattern replace = Pattern.compile("\\s+"); + Matcher matcher2 = replace.matcher(EXAMPLE_TEST); + System.out.println(matcher2.replaceAll("\t")); + + //use Java to print out a long string with \n inside + System.out.println("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDF3xdggzWiOsbZ\nETP5JSQswsCA7PGijDAM19Vg78rPii2kWBJ7mT8SbE+3UVZgZQeHpXsD4dz+7PY2\n3HJVxPI/xHFmukarX9LM9FRcPCWnjZDC8OqlbpDPwUyHU98EMfAxCtmie/LtnxCv\nbtXLEpCV/E8Y14aJOMzwQAwc/qbcTX4cqw/gMgcNogYHcuNCIxlNAIOnsXsNm6jx\nx0spL9Z/5Cny0ys/+GkxMi1rTZROESdYI0xwHSMcl8SjO2z1aejdRC2U/3jb4X/n\nmbjAzHfFTdjtxU5b9e9xPuD2+/tv8ug8cm1HjNrxhTwcW7chqUeQAxB6Dd5kPV3n\n7pkHy/8HAgMBAAECggEAGVclvkVvc/RFDP2IA2s/Q8A5OQmfNGrxqGNnvz9WYNfY\nWoiw7UVF740RdG+lOTkXCsclhuzBCaC9M29t8RAE2ifFQhuu+zmNXJQZzaoiRF/7\n3wtNcZxETWb67wXNtNLUaONz1bw78zSAxYbTOGuLOroSQyMu5pnwnQAGzRvLsMC9\n1RnrV7kPgdf0iVbKjVGXW2TzLmiVNxnglXFAYM406vblcZaWBcdSPuSAZs7WPlle\nYOgtwcNX1TPBoujy3tMRBjjJPUt1yixgp74iKThG5FC6YCy9/MWfX9WE27/SsIh6\nC+nFJaVMwl/2iLQ123UH0kouIb9Nckmdsk6R+uSN8QKBgQD8QJhiNoPY3HARZLgZ\nqj9gbp0/170z2nii7wT/8ynQij207kFYjUnOC78KJsFmrKyf2dicoIxu6fj0cL6A\nOdLIFpmVByy6pAJpSW73xirzhmYt2f05a4D/A3LkfmwdsZ1x4DQx4U9PgKgJpIYs\n+cuGzSee0uylImLnlwqbQG0LCQKBgQDIz6qX5USrGWPInOTSb3h1N3FuOqfxrtFp\nKWjWimdU9BmuArVHHIrrHW9/xQsnpX3iaQPfTbeDpy32VZulhLhJs028JZu+/fGb\nqYUiDgwOJ+sYCC/3H5/KGt2/Xjfi213Fh9XiWj1ZbZvdj9Dygwn4yGiP4dUGVQGo\nP9zQj7BtjwKBgAQZZKCL9D6M7oFJ2rgIDTma8pE8B0YVccpsCe/C2tYZuQD8sjEn\nMqDXjgYzNQdfHPsIBj4dWcrfoH0Qa/gXeHZp75r9X9u0mJlvaQ87uCz27Sgnl7bc\nKV97hd1ytH0TCtTz6MU6vRg0pgZqFwgaExWgtdkd4lyYn3TV/oUhWeRJAoGAJX+R\n7ZdkgUbWeUnC+QDTz5+w0NKnNdxdQnP3HcjujtCeUv4yd7r+vfTbM1LKSHcA0Nyn\nWnWaxTzculk2HWxxNWIELBQhx0KIcXbwY3GYErSlk/FDc7Q2FHl72xZu/S/VjONW\nr1QGjMKJDpCihgauQAS8cdHMA8iv7IkwZMnQOkUCgYEA6yVXJ9It1fE1eisK2NY5\nfkLw1iviBWpZ4mgipTTglP5K3CEG1ygDs7PJOP0JEiDWPWf8PmvROUp1k9x+nKFP\nekd2qwZEul9Pr0jaD3y9dnpK3Sg4qxKhlRy0to3xzszbyL7gmP8l/9yxcbTyIRLT\nWDZrtCj706FGRFx/QkUkku0="); + } +} + diff --git a/src/sporadic/SendEmail.java b/src/main/java/sporadic/SendEmail.java similarity index 100% rename from src/sporadic/SendEmail.java rename to src/main/java/sporadic/SendEmail.java diff --git a/src/sporadic/UnderstandClass.java b/src/main/java/sporadic/UnderstandClass.java similarity index 100% rename from src/sporadic/UnderstandClass.java rename to src/main/java/sporadic/UnderstandClass.java diff --git a/src/main/java/sporadic/UnderstandingJavaReference.java b/src/main/java/sporadic/UnderstandingJavaReference.java new file mode 100644 index 0000000..03a42c3 --- /dev/null +++ b/src/main/java/sporadic/UnderstandingJavaReference.java @@ -0,0 +1,25 @@ +package sporadic; + +/** + * Created by stevesun on 12/29/16. + */ +public class UnderstandingJavaReference { + /**This is a good example to understand how references work in Java.*/ + public static void main(String[] args) { + /**String.replace() method has a return value, this method actually creates a new string + * to return, these four lines of code assign the newly created string to this reference 'a', + * that's why a got changed the second time I print it out.*/ + String a = "ABCabc"; + System.out.println(a); + a = a.replace('A', 'a'); + System.out.println(a); + + /**Here, we didn't assign the newly created string to ss, that's why ss didn't change when + * I print it out the second time. + * I can find more details if I open up String.replace() method.*/ + String ss = "123456"; + System.out.println(ss); + ss.replace('1', '0'); + System.out.println(ss); + } +} diff --git a/src/spring-configuration/json-spring-configuration.xml b/src/main/java/spring-configuration/json-spring-configuration.xml similarity index 100% rename from src/spring-configuration/json-spring-configuration.xml rename to src/main/java/spring-configuration/json-spring-configuration.xml diff --git a/src/spring-configuration/serialization-spring-configuration.xml b/src/main/java/spring-configuration/serialization-spring-configuration.xml similarity index 100% rename from src/spring-configuration/serialization-spring-configuration.xml rename to src/main/java/spring-configuration/serialization-spring-configuration.xml diff --git a/src/main/java/string/UnderstandStringInJava.java b/src/main/java/string/UnderstandStringInJava.java new file mode 100644 index 0000000..f431629 --- /dev/null +++ b/src/main/java/string/UnderstandStringInJava.java @@ -0,0 +1,29 @@ +package string; + +public class UnderstandStringInJava { + public static void main(String... args) { + UnderstandStringInJava understandStringInJava = new UnderstandStringInJava(); + understandStringInJava.checkStringEquality(); + System.out.println("Program finished."); + } + + public void checkStringEquality() { + String a = "abc"; + String b = "abc"; + + /** + * One can use == operators for reference comparison (address comparison) and the .equals() method for content comparison. + * Both s1 and s2 refer to different objects. + * When one uses == operator for the s1 and s2 comparison then the result is false as both have different addresses in memory. + * Using equals, the result is true because it’s only comparing the values given in s1 and s2.*/ + System.out.println(a == b); + System.out.println(a.equals(b)); + + String c = new String(new char[]{'a', 'b', 'c', 'd'}); + String d = new String(new char[]{'a', 'b', 'c', 'd'}); + System.out.println("c is: " + c); + System.out.println("d is: " + d); + System.out.println(c == d); + System.out.println(c.equals(d)); + } +} diff --git a/src/main/resources/queen-mary.png b/src/main/resources/queen-mary.png new file mode 100644 index 0000000..defe6e4 Binary files /dev/null and b/src/main/resources/queen-mary.png differ diff --git a/src/sporadic/customize_annotations_generics_wildcards_examples/MyTestState.java b/src/sporadic/customize_annotations_generics_wildcards_examples/MyTestState.java deleted file mode 100644 index 113a571..0000000 --- a/src/sporadic/customize_annotations_generics_wildcards_examples/MyTestState.java +++ /dev/null @@ -1,5 +0,0 @@ -package sporadic.customize_annotations_generics_wildcards_examples; - -public enum MyTestState { - ACTIVE, INACTIVE -} diff --git a/src/sporadic/java_async_method_example/async/method/AsyncClient.java b/src/sporadic/java_async_method_example/async/method/AsyncClient.java deleted file mode 100644 index 199abeb..0000000 --- a/src/sporadic/java_async_method_example/async/method/AsyncClient.java +++ /dev/null @@ -1,8 +0,0 @@ -package sporadic.java_async_method_example.async.method; - -public interface AsyncClient { - - // for asynchronous - public void executeAsynchronous(final String userId); - -} diff --git a/src/sporadic/java_async_method_example/async/method/AsyncClientImpl.java b/src/sporadic/java_async_method_example/async/method/AsyncClientImpl.java deleted file mode 100644 index 594e2c7..0000000 --- a/src/sporadic/java_async_method_example/async/method/AsyncClientImpl.java +++ /dev/null @@ -1,36 +0,0 @@ -package sporadic.java_async_method_example.async.method; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -public class AsyncClientImpl implements AsyncClient { - ExecutorService executor = Executors.newFixedThreadPool(3); - - @Override - public void executeAsynchronous(String userId) { - List> list = new ArrayList>(); - - Callable callable = new Task(userId); - - for(int i = 0; i < 10; i++) { - Future future = executor.submit(callable); - list.add(future); - } - - for(Future future : list){ - try { - System.out.println(new Date() + " " + future.get()); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); - } - } - System.out.println("That's the end of the executeAsynchronous method!"); - executor.shutdown(); - } -} diff --git a/src/sporadic/java_async_method_example/async/method/MainApp.java b/src/sporadic/java_async_method_example/async/method/MainApp.java deleted file mode 100644 index 1d90ed5..0000000 --- a/src/sporadic/java_async_method_example/async/method/MainApp.java +++ /dev/null @@ -1,18 +0,0 @@ -package sporadic.java_async_method_example.async.method; - -/**This package was used to demo the difference between sync and async methods, but right now, there's really no difference between the impl of SyncClientImpl and AsyncClientImpl classes, - * I need to rewrite them to deepen my understanding!*/ -public class MainApp { - - public static void main(String... args) { - SyncClient syncClient = new SyncClientImpl(); - - syncClient.executeSynchronous("this is executing synchronous method!"); - - AsyncClient asyncClient = new AsyncClientImpl(); - asyncClient - .executeAsynchronous("this is executing Asynchronous method!"); - - System.out.println("That's the end of MainApp!"); - } -} diff --git a/src/sporadic/java_async_method_example/async/method/SyncClient.java b/src/sporadic/java_async_method_example/async/method/SyncClient.java deleted file mode 100644 index 4b9a1c4..0000000 --- a/src/sporadic/java_async_method_example/async/method/SyncClient.java +++ /dev/null @@ -1,6 +0,0 @@ -package sporadic.java_async_method_example.async.method; - -public interface SyncClient { - // for synchronous - public void executeSynchronous(final String userId); -} diff --git a/src/sporadic/java_async_method_example/async/method/SyncClientImpl.java b/src/sporadic/java_async_method_example/async/method/SyncClientImpl.java deleted file mode 100644 index e74ded4..0000000 --- a/src/sporadic/java_async_method_example/async/method/SyncClientImpl.java +++ /dev/null @@ -1,36 +0,0 @@ -package sporadic.java_async_method_example.async.method; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -public class SyncClientImpl implements SyncClient { - ExecutorService executor = Executors.newFixedThreadPool(3); - - @Override - public void executeSynchronous(String userId) { - List> list = new ArrayList>(); - - Callable callable = new Task(userId); - - for(int i = 0; i < 10; i++) { - Future future = executor.submit(callable); - list.add(future); - } - - for(Future future : list){ - try { - System.out.println(new Date() + " " + future.get()); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); - } - } - executor.shutdown(); - System.out.println("That's the end of the executeSynchronous method!"); - } -} diff --git a/src/sporadic/java_async_method_example/async/method/Task.java b/src/sporadic/java_async_method_example/async/method/Task.java deleted file mode 100644 index 6d6732c..0000000 --- a/src/sporadic/java_async_method_example/async/method/Task.java +++ /dev/null @@ -1,19 +0,0 @@ -package sporadic.java_async_method_example.async.method; - -import java.util.concurrent.Callable; - -public class Task implements Callable { - - private final String userId; - - public Task(String userId) { - this.userId = userId; - } - - @Override - public String call() throws Exception { - Thread.sleep(1500); - return Thread.currentThread().getName() + " " + userId; - } - -} diff --git a/src/sporadic/semaphore/ConnectionLimiter.java b/src/sporadic/semaphore/ConnectionLimiter.java deleted file mode 100644 index 3f048c1..0000000 --- a/src/sporadic/semaphore/ConnectionLimiter.java +++ /dev/null @@ -1,71 +0,0 @@ -package sporadic.semaphore; - -import java.util.concurrent.Semaphore; - -/** - * This is a small program to demo how semaphore can create trouble for us. - * One rule of thumb is: - * Always release what you acquire! - * Copied from online. - * - */ -//this is a bad public class name, it doesn't apply to -//what this class really do, it's a name from a different class that I copied earlier. -public class ConnectionLimiter { - - private static class DoubleResourceGrabber implements Runnable{ - - private Semaphore first; - private Semaphore second; - - public DoubleResourceGrabber(Semaphore s1, Semaphore s2){ - first = s1; - second = s2; - } - - @Override - public void run() { - Thread t = Thread.currentThread(); - - try { - first.acquire(); - System.out.println(t.getName() + " acquired " + first); - -// Thread.sleep(20);//to demo a deadlock - -// second.acquire(); -// System.out.println(t.getName() + " acquired " + second); - -// second.release(); -// System.out.println(t.getName() + " released " + second); - - first.release(); - System.out.println(t.getName() + " released " + first); - - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - /** - * @param args - * @throws InterruptedException - */ - public static void main(String[] args) throws InterruptedException { - Semaphore s1 = new Semaphore(1);//give it only 1 permit - Semaphore s2 = new Semaphore(1);//give it only 1 permit as well - Thread t1 = new Thread(new DoubleResourceGrabber(s1, s2)); - //now reverse them, here comes the trouble - Thread t2 = new Thread(new DoubleResourceGrabber(s2, s1)); - - t1.start(); - t2.start(); - - t1.join(); - t2.join(); - System.out.println("We got lucky!"); - - } - -} diff --git a/src/sporadic/thread/ThreadIsCool.java b/src/sporadic/thread/ThreadIsCool.java deleted file mode 100644 index d2a78c7..0000000 --- a/src/sporadic/thread/ThreadIsCool.java +++ /dev/null @@ -1,56 +0,0 @@ -package sporadic.thread; - -/** This is a cool and small program to show that threads don't run in the order that you can control, it's all scheduled by the thing called - * Thread Scheduler.*/ - -public class ThreadIsCool implements Runnable{ - - public static void main(String [] args){ - ThreadIsCool threadIsCool = new ThreadIsCool(); - Thread abc = new Thread(threadIsCool); - Thread def = new Thread(threadIsCool); - Thread ghi = new Thread(threadIsCool); - abc.setName("abc"); - def.setName("def"); - ghi.setName("ghi"); - System.out.println("Now the three threads kick off:"); - - abc.start(); - try { - /* Start second thread(def) only when first thread(abc) is dead*/ - abc.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - def.start(); - try { - def.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - ghi.start(); - try { - ghi.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - System.out.println("Now the Program ended."); - } - - @Override - public void run(){ - for(int i = 0; i < 5; i++){ - String threadName = Thread.currentThread().getName(); - System.out.println(threadName + " is running!"); - } - System.out.println(Thread.currentThread().getName() + " is sleeping for 3 seconds"); - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - -} diff --git a/src/sporadic/thread/ThreadLocalExample.java b/src/sporadic/thread/ThreadLocalExample.java deleted file mode 100644 index 3fba541..0000000 --- a/src/sporadic/thread/ThreadLocalExample.java +++ /dev/null @@ -1,49 +0,0 @@ -package sporadic.thread; - -/** - * The ThreadLocal class in Java enables you to create variables that can only - * be read and written by the same thread. Thus, even if two threads are - * executing the same code, and the code has a reference to a ThreadLocal - * variable, then the two threads cannot see each other's ThreadLocal variables. - * - * Since values set on a ThreadLocal object only are visible to the thread who - * set the value, no thread can set an initial value on a ThreadLocal using - * set() which is visible to all threads. - * Instead you can specify an initial value for a ThreadLocal object by - * subclassing ThreadLocal and overriding the initialValue() method. Here is how - * that looks: - * - * private ThreadLocal myThreadLocal = new ThreadLocal() { - * @Override - * protected String initialValue() { return "This is the initial value"; } - * }; - */ - -public class ThreadLocalExample { - - public static class MyRunnable implements Runnable { - - private ThreadLocal threadLocal = new ThreadLocal(); - - @Override - public void run() { - threadLocal.set((int) (Math.random() * 100D)); - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - System.out.println("threadLocal.get() is: " + threadLocal.get()); - } - - public static void main(String... args) { - MyRunnable sharedRunnableInstance = new MyRunnable(); - Thread t1 = new Thread(sharedRunnableInstance); - Thread t2 = new Thread(sharedRunnableInstance); - - t1.start(); - t2.start(); - } - } - -} diff --git a/src/sporadic/thread/synchronization/withoutSynchronization/TestThread.java b/src/sporadic/thread/synchronization/withoutSynchronization/TestThread.java deleted file mode 100644 index e71367f..0000000 --- a/src/sporadic/thread/synchronization/withoutSynchronization/TestThread.java +++ /dev/null @@ -1,73 +0,0 @@ -/** - * - */ -package sporadic.thread.synchronization.withoutSynchronization; - -/** - * @author jiahuan - * This produces DIFFERENT result every time you run this program, in contrast to the one with synchronization. - * Here is a simple example which may or may not print counter value in sequence and every time we run it, it produces different result based on CPU availability to a thread. - * Copied from this link: http://www.tutorialspoint.com/java/java_thread_synchronization.htm, refer to this link for further info. - * - */ -public class TestThread { - public static void main(String args[]) { - - PrintDemo PD = new PrintDemo(); - - ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD ); - ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD ); - - T1.start(); - T2.start(); - - // wait for threads to end - try { - T1.join(); - T2.join(); - } catch( Exception e) { - System.out.println("Interrupted"); - } - } - -} - - -class PrintDemo { - public void printCount(){ - try { - for(int i = 5; i > 0; i--) { - System.out.println("Counter --- " + i ); - } - } catch (Exception e) { - System.out.println("Thread interrupted."); - } - } - - } - - class ThreadDemo extends Thread { - private Thread t; - private String threadName; - PrintDemo PD; - - ThreadDemo( String name, PrintDemo pd){ - threadName = name; - PD = pd; - } - public void run() { - PD.printCount(); - System.out.println("Thread " + threadName + " exiting."); - } - - public void start () - { - System.out.println("Starting " + threadName ); - if (t == null) - { - t = new Thread (this, threadName); - t.start (); - } - } - - } diff --git a/src/test/b2SdkExamples/B2JsonTest.java b/src/test/b2SdkExamples/B2JsonTest.java new file mode 100644 index 0000000..3181255 --- /dev/null +++ b/src/test/b2SdkExamples/B2JsonTest.java @@ -0,0 +1,444 @@ +package b2SdkExamples; + +import com.backblaze.b2.json.B2Json; +import com.backblaze.b2.json.B2JsonException; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.skyscreamer.jsonassert.JSONAssert; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * Reference: https://github.com/Backblaze/b2-sdk-java/blob/0ecd68df94691cbba5a6af363246b7193aead234/core/src/test/java/com/backblaze/b2/json/B2JsonTest.java + */ +public class B2JsonTest { + + private static final LocalDateTime LOCAL_DATE_TIME = LocalDateTime.of(2022, 12, 18, 16, 21); + private static final LocalDate LOCAL_DATE = LocalDate.of(2022, 12, 18); + + private static final String JSON_STRING_1 = "{\n" + +// " \"localDate\": \"20221218\",\n" + +// " \"localDateTime\": \"d20221218_m162100\",\n" + + " \"message\": \"message\",\n" + + " \"str\": 123,\n" + + " \"reason\": \"A TEST STRING FOR REASON\"\n" + + "}"; + + private static final String JSON_STRING_2 = "{\n" + + " \"aMessage\": \"aMessage\",\n" + + " \"bMessage\": \"bMessage\",\n" + + " \"message\": \"message\",\n" + + " \"pMessage\": \"pMessage\",\n" + + " \"reason\": \"A TEST STRING FOR REASON\",\n" + + " \"str\": 123,\n" + + " \"zMessage\": \"zMessage\"\n" + + "}"; + private static final String REASON_STR = "A TEST STRING FOR REASON"; + + private static final class Container { + + @B2Json.required + public final int a; + + @B2Json.optional + public final String b; + + @B2Json.ignored + public int c; + + @B2Json.optionalWithDefault(defaultValue = "0") + public int d; + + @B2Json.constructor(params = "a, b, d") + public Container(int a, String b, int d) { + this.a = a; + this.b = b; + this.c = 5; + this.d = d; + } + + @Override + public boolean equals(Object o) { + System.out.println("Entered overridden equals() method to check now..."); + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Container container = (Container) o; + return a == container.a && d == container.d && Objects.equals(b, container.b); + } + + @Override + public int hashCode() { + return Objects.hash(a, b, c, d); + } + } + + private static final B2Json b2Json = B2Json.get(); + private static final Gson gson = (new GsonBuilder()) + .disableHtmlEscaping() + .setPrettyPrinting().create(); + + private static class TestRequest { + @B2Json.optional(omitNull = true) + public final Integer str; + + @B2Json.optional(omitNull = true) + public final String message; + + @B2Json.optional(omitNull = true) + public final String aMessage; + + @B2Json.optional(omitNull = true) + public final String bMessage; + + @B2Json.optional(omitNull = true) + public final String pMessage; + + @B2Json.optional(omitNull = true) + public final String zMessage; + + @B2Json.optional(omitNull = true) + public final LocalDateTime localDateTime; + + @B2Json.optional(omitNull = true) + public final LocalDate localDate; + + @B2Json.optional(omitNull = true) + public final String reason; + + @B2Json.constructor(params = "" + + "str," + + "message," + + "aMessage," + + "bMessage," + + "pMessage," + + "zMessage," + + "localDateTime," + + "localDate," + + "reason" + ) + public TestRequest(Integer str, String message, String aMessage, String bMessage, String pMessage, String zMessage, LocalDateTime localDateTime, LocalDate localDate, String reason) { + this.str = str; + this.message = message; + this.aMessage = aMessage; + this.bMessage = bMessage; + this.pMessage = pMessage; + this.zMessage = zMessage; + this.localDateTime = localDateTime; + this.localDate = localDate; + this.reason = reason; + } + } + + private static class TestResponse { + @B2Json.optional(omitNull = true) + public final String str; + + @B2Json.optional(omitNull = true) + public final String message; + + @B2Json.optional(omitNull = true) + public final String reason; + + @B2Json.optional(omitNull = true) + public final Boolean succeeded; + + @B2Json.optional(omitNull = true) + public final Integer status; + + @B2Json.optional(omitNull = true) + public final LocalDateTime localDateTime; + + @B2Json.optional(omitNull = true) + public final LocalDate localDate; + + @B2Json.required + public final Map> revenueMap; + + @B2Json.required + public final Map simpleMap; + + @B2Json.required + public final Set categories; + + @B2Json.constructor(params = "" + + "str," + + "message," + + "reason," + + "succeeded," + + "status," + + "localDateTime," + + "localDate," + + "revenueMap," + + "simpleMap," + + "categories" + ) + public TestResponse(String str, String message, String reason, boolean succeeded, int status, LocalDateTime localDateTime, LocalDate localDate, + Map> revenueMap, + Map simpleMap, + Set categories) { + this.str = str; + this.message = message; + this.reason = reason; + this.succeeded = succeeded; + this.status = status; + this.localDateTime = localDateTime; + this.localDate = localDate; + this.simpleMap = simpleMap; + this.revenueMap = revenueMap; + this.categories = categories; + } + } + + @Test + public void testResponseUsingB2Json() throws B2JsonException, JSONException { + Map> revenueMap = new TreeMap<>(); + Map simpleMap = new TreeMap<>(); + TestResponse obj = new TestResponse("str", + "message", + "reason", + true, + 200, + LocalDateTime.of(2023, 03, 31, 12, 21), + LocalDate.of(2023, 03, 31), + revenueMap, + simpleMap, + Set.of("test1", "test2")); + System.out.println("obj is: " + obj); + String expected = "{\n" + + " \"categories\": [\n" + + " \"test2\",\n" + + " \"test1\"\n" + + " ],\n" + + " \"localDate\": \"20230331\",\n" + + " \"localDateTime\": \"d20230331_m122100\",\n" + + " \"message\": \"message\",\n" + + " \"reason\": \"reason\",\n" + + " \"revenueMap\": {},\n" + + " \"simpleMap\": {},\n" + + " \"status\": 200,\n" + + " \"str\": \"str\",\n" + + " \"succeeded\": true\n" + + "}"; + System.out.println("b2Json.toJson(obj): " + b2Json.toJson(obj)); + JSONAssert.assertEquals(expected, b2Json.toJson(obj), true); + } + + @Test + public void testResponseUsingGson() throws JSONException { + Map> revenueMap = new TreeMap<>(); + revenueMap.put("123", new HashMap<>()); + Map simpleMap = new TreeMap<>(); + TestResponse obj = new TestResponse("str", + "message", + "reason", + true, + 200, + LocalDateTime.of(2023, 03, 31, 12, 21), + LocalDate.of(2023, 03, 31), + revenueMap, + simpleMap, + Set.of("test")); + String expected = "{\n" + + " \"str\": \"str\",\n" + + " \"message\": \"message\",\n" + + " \"reason\": \"reason\",\n" + + " \"succeeded\": true,\n" + + " \"status\": 200,\n" + + " \"localDateTime\": {\n" + + " \"date\": {\n" + + " \"year\": 2023,\n" + + " \"month\": 3,\n" + + " \"day\": 31\n" + + " },\n" + + " \"time\": {\n" + + " \"hour\": 12,\n" + + " \"minute\": 21,\n" + + " \"second\": 0,\n" + + " \"nano\": 0\n" + + " }\n" + + " },\n" + + " \"localDate\": {\n" + + " \"year\": 2023,\n" + + " \"month\": 3,\n" + + " \"day\": 31\n" + + " },\n" + + " \"revenueMap\": {\n" + + " \"123\": {}\n" + + " },\n" + + " \"simpleMap\": {},\n" + + " \"categories\": [\n" + + " \"test\"\n" + + " ]\n" + + "}"; + JSONAssert.assertEquals(expected, gson.toJson(obj), true); + } + + @Test + public void testObject() throws B2JsonException { + String json = "{\n" + + " \"a\": 41,\n" + + " \"b\": \"hello\",\n" + + " \"d\": 15\n" + + "}"; + Container obj = new Container(41, "hello", 15); + assertEquals(json, b2Json.toJson(obj)); + System.out.println("obj is: " + obj); + System.out.println("json is: " + json); + assertEquals(obj, b2Json.fromJson(json, Container.class)); + } + + @Test + public void testObjectUsingDefaultValue() throws B2JsonException { + //in this json string, there's no field d which is an optional field with a default value + String json = "{\n" + + " \"a\": 2023,\n" + + " \"b\": \"hello\"\n" + + "}"; + System.out.println("json is: " + json); + Container fromB2Json = b2Json.fromJson(json, Container.class); + System.out.println("b2Json.fromJson(json, Container.class) is: " + fromB2Json); + Container fromGson = gson.fromJson(json, Container.class); + System.out.println("gson.fromJson(json) is: " + fromGson); + System.out.println("about to check the equality between Gson and B2Json results.."); + assertEquals(fromGson, fromB2Json); + String fromB2JsonString = b2Json.toJson(fromB2Json); + String fromGsonString = gson.toJson(fromGson); + String expectedFromGson = "{\n" + + " \"a\": 2023,\n" + + " \"b\": \"hello\",\n" + + " \"c\": 0,\n" + + " \"d\": 0\n" + + "}"; + assertEquals(expectedFromGson, fromGsonString); + //there's no field c as it's annotated by B2Json.ignored + String expectedFromB2Json = "{\n" + + " \"a\": 2023,\n" + + " \"b\": \"hello\",\n" + + " \"d\": 0\n" + + "}"; + assertEquals(expectedFromB2Json, fromB2JsonString); + } + + @Test + public void testRequestUsingB2Json() throws B2JsonException, JSONException { + //B2Json always reorders the fields in the object in alphabetical order + TestRequest obj = new TestRequest(123, "message", "aMessage", "bMessage", "pMessage", "zMessage", null, null, REASON_STR); + System.out.println("obj is: " + obj); + String expected = "{\n" + + " \"aMessage\": \"aMessage\",\n" + + " \"bMessage\": \"bMessage\",\n" + + " \"message\": \"message\",\n" + + " \"pMessage\": \"pMessage\",\n" + + " \"reason\": \"A TEST STRING FOR REASON\",\n" + + " \"str\": 123,\n" + + " \"zMessage\": \"zMessage\"\n" + + "}"; + JSONAssert.assertEquals(expected, b2Json.toJson(obj), true); + } + + @Test + public void testRequestUsingGson() throws JSONException { + //GSON deserializes object fields in their given order in the constructor + TestRequest obj = new TestRequest(123, "message", "aMessage", "bMessage", "pMessage", "zMessage", null, null, REASON_STR); + System.out.println("obj is: " + obj); + String expected = "{\n" + + " \"aMessage\": \"aMessage\",\n" + + " \"bMessage\": \"bMessage\",\n" + + " \"message\": \"message\",\n" + + " \"pMessage\": \"pMessage\",\n" + + " \"reason\": \"A TEST STRING FOR REASON\",\n" + + " \"str\": 123,\n" + + " \"zMessage\": \"zMessage\"\n" + + "}"; + JSONAssert.assertEquals(expected, gson.toJson(obj), false); + } + + @Test + public void testRequest2UsingB2Json() { + /** + * the field zip is declared as an Integer, but we are passing in a string, in this case + * it throws com.backblaze.b2.json.B2JsonException: Bad number + * */ + String request2Json = "{\n" + "\"zip\": \"95148\"\n" + "}"; + assertThrows(B2JsonException.class, () -> b2Json.fromJson(request2Json, TestRequest2.class)); + } + + private static class TestRequest2 { + @B2Json.optional(omitNull = true) + public final Integer zip; + + @B2Json.constructor(params = "zip") + public TestRequest2(Integer zip) { + this.zip = zip; + } + } + + @Test + public void testRequest3UsingB2Json() { + /** + * the field zip is declared as a String, but we are passing in an Integer + * in this case, it throws: com.backblaze.b2.json.B2JsonException: string does not start with quote + * */ + String request2Json = "{\n" + "\"zip\": 95148\n" + "}"; + assertThrows(B2JsonException.class, () -> b2Json.fromJson(request2Json, TestRequest3.class)); + } + + private static class TestRequest3 { + @B2Json.optional(omitNull = true) + public final String zip; + + @B2Json.constructor(params = "zip") + public TestRequest3(String zip) { + this.zip = zip; + } + } + + @Test + public void testGsonFailure() { + // there's an unknown field called e in this json string, in this case, GSON library will just ignore it + String json = "{\n" + + " \"a\": 2023,\n" + + " \"b\": \"hello\",\n" + + " \"e\": \"hello\"\n" + + "}"; + System.out.println("json is: " + json); + Container fromGson = gson.fromJson(json, Container.class); + System.out.println("gson.fromJson(json) is: " + fromGson); + System.out.println("about to check the equality between Gson and B2Json results.."); + String fromGsonString = gson.toJson(fromGson); + String expectedFromGson = "{\n" + + " \"a\": 2023,\n" + + " \"b\": \"hello\",\n" + + " \"c\": 0,\n" + + " \"d\": 0\n" + + "}"; + assertEquals(expectedFromGson, fromGsonString); + + // in this json, the field named a is missing + json = "{\n" + + " \"b\": \"hello\",\n" + + " \"e\": \"hello\"\n" + + "}"; + System.out.println("2nd time, json is: " + json); + fromGson = gson.fromJson(json, Container.class); + System.out.println("2nd time, gson.fromJson(json) is: " + fromGson); + System.out.println("about to check the equality between Gson and B2Json results.."); + fromGsonString = gson.toJson(fromGson); + System.out.println("2nd time, fromGsonString is: " + fromGsonString); + expectedFromGson = "{\n" + + " \"a\": 0,\n" + + " \"b\": \"hello\",\n" + + " \"c\": 0,\n" + + " \"d\": 0\n" + + "}"; + assertEquals(expectedFromGson, fromGsonString); + } +} diff --git a/src/test/guice/MyApplicationTest.java b/src/test/guice/MyApplicationTest.java new file mode 100644 index 0000000..8920606 --- /dev/null +++ b/src/test/guice/MyApplicationTest.java @@ -0,0 +1,37 @@ +package guice; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class MyApplicationTest { + + private Injector injector; + + @Before + public void setUp() { + injector = Guice.createInjector(new AbstractModule() { + + @Override + protected void configure() { + bind(MessageService.class).to(MockMessageService.class); + } + }); + } + + @After + public void tearDown() { + injector = null; + } + + @Test + public void test() { + MyApplication appTest = injector.getInstance(MyApplication.class); + Assert.assertEquals(true, appTest.sendMessage("Hi Steve", "fishercoder@gmail.com")); + ; + } +} diff --git a/src/test/junit5/BaseTest.java b/src/test/junit5/BaseTest.java new file mode 100644 index 0000000..073f751 --- /dev/null +++ b/src/test/junit5/BaseTest.java @@ -0,0 +1,6 @@ +package junit5; + +public class BaseTest { + protected String field1; + protected Integer field2; +} diff --git a/src/test/junit5/ChildTest.java b/src/test/junit5/ChildTest.java new file mode 100644 index 0000000..aff3b9f --- /dev/null +++ b/src/test/junit5/ChildTest.java @@ -0,0 +1,22 @@ +package junit5; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertNull; + +public class ChildTest extends BaseTest { + + private static Stream data() { + return Stream.of(Arguments.of("string1")); + } + + @ParameterizedTest + @MethodSource("data") + public void test1() { + assertNull(this.field2); + } +} diff --git a/src/test/junit5/FirstParallelUnitTest.java b/src/test/junit5/FirstParallelUnitTest.java new file mode 100644 index 0000000..a82734d --- /dev/null +++ b/src/test/junit5/FirstParallelUnitTest.java @@ -0,0 +1,19 @@ +package junit5; + +import org.junit.jupiter.api.Test; + +public class FirstParallelUnitTest { + @Test + public void first() throws Exception { + System.out.println("FirstParallelUnitTest first() start => " + Thread.currentThread().getName()); + Thread.sleep(500); + System.out.println("FirstParallelUnitTest first() end => " + Thread.currentThread().getName()); + } + + @Test + public void second() throws Exception { + System.out.println("FirstParallelUnitTest second() start => " + Thread.currentThread().getName()); + Thread.sleep(500); + System.out.println("FirstParallelUnitTest second() end => " + Thread.currentThread().getName()); + } +} diff --git a/src/test/junit5/Junit5Test.java b/src/test/junit5/Junit5Test.java new file mode 100644 index 0000000..d6352a5 --- /dev/null +++ b/src/test/junit5/Junit5Test.java @@ -0,0 +1,58 @@ +package junit5; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class Junit5Test { + @BeforeAll + static void setup() { + System.out.println("@BeforeAll - executes once before all test methods in this class"); + } + + @BeforeEach + void init() { + System.out.println("@BeforeEach - executes before each test method in this class"); + } + + @DisplayName("Single test successful") + @Test + void testSingleSuccessTest() { + System.out.println("in testSingleSuccessTest"); + assertEquals(5 + 2, 7); + } + + @Test + void shouldThrowException() { + System.out.println("in shouldThrowException"); + Throwable exception = assertThrows(UnsupportedOperationException.class, () -> { + throw new UnsupportedOperationException("Not supported"); + }); + assertEquals("Not supported", exception.getMessage()); + } + + @Test + void assertThrowsException() { + System.out.println("in assertThrowsException"); + String str = null; + assertThrows(IllegalArgumentException.class, () -> { + Integer.valueOf(str); + }); + } + + @AfterEach + void tearDown() { + System.out.println("@AfterEach - executed after each test method."); + } + + @AfterAll + static void done() { + System.out.println("@AfterAll - executed after all test methods."); + } +} diff --git a/src/test/junit5/ParameterizedTestExampleTest.java b/src/test/junit5/ParameterizedTestExampleTest.java new file mode 100644 index 0000000..e856e13 --- /dev/null +++ b/src/test/junit5/ParameterizedTestExampleTest.java @@ -0,0 +1,28 @@ +package junit5; + +import org.apache.logging.log4j.util.Strings; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ParameterizedTestExampleTest { + @ParameterizedTest + @MethodSource("data") + public void parameterizedTest(String input, boolean expected) { + System.out.println("input is: " + input + ", expected is: " + expected); + assertEquals(expected, Strings.isBlank(input)); + } + + private static Stream data() { + return Stream.of( + Arguments.of(null, true), + Arguments.of("", true), + Arguments.of(" ", true), + Arguments.of("not blank", false) + ); + } +} diff --git a/src/test/junit5/SecondParallelUnitTest.java b/src/test/junit5/SecondParallelUnitTest.java new file mode 100644 index 0000000..5daf074 --- /dev/null +++ b/src/test/junit5/SecondParallelUnitTest.java @@ -0,0 +1,19 @@ +package junit5; + +import org.junit.jupiter.api.Test; + +public class SecondParallelUnitTest { + @Test + public void first() throws Exception { + System.out.println("SecondParallelUnitTest first() start => " + Thread.currentThread().getName()); + Thread.sleep(500); + System.out.println("SecondParallelUnitTest first() end => " + Thread.currentThread().getName()); + } + + @Test + public void second() throws Exception { + System.out.println("SecondParallelUnitTest second() start => " + Thread.currentThread().getName()); + Thread.sleep(500); + System.out.println("SecondParallelUnitTest second() end => " + Thread.currentThread().getName()); + } +} diff --git a/src/test/resources/city_names.csv b/src/test/resources/city_names.csv new file mode 100644 index 0000000..2ee71fd --- /dev/null +++ b/src/test/resources/city_names.csv @@ -0,0 +1 @@ +NYC,NYC,NYC,Cedar Park,NYC,NYC,NYC,NYC,San Jose,San Jose,San Jose,San Jose,McKinney,San Jose,SF,LA,LA,LA,LA,LA,San Diego,San Diego,San Diego,Seattle,Portland,Portland,Portland,Boston,D.C,D.C,D.C,Miami,Dallas,Cedar Park,McKinney,Melissa,Sacramento,Sacramento \ No newline at end of file diff --git a/src/test/resources/junit-platform.properties b/src/test/resources/junit-platform.properties new file mode 100644 index 0000000..ad19ea8 --- /dev/null +++ b/src/test/resources/junit-platform.properties @@ -0,0 +1,3 @@ +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = concurrent \ No newline at end of file diff --git a/src/test/resources/sample_input.txt b/src/test/resources/sample_input.txt new file mode 100644 index 0000000..10a9d37 --- /dev/null +++ b/src/test/resources/sample_input.txt @@ -0,0 +1 @@ +cool test it is \ No newline at end of file diff --git a/src/test/resources/values_with_comma_inside.csv b/src/test/resources/values_with_comma_inside.csv new file mode 100644 index 0000000..32d8d9c --- /dev/null +++ b/src/test/resources/values_with_comma_inside.csv @@ -0,0 +1,5 @@ +fjdosibv,FixIT LLC +98cdsjoin,"JACKSON ABC, LLC. " +1234,Campers Nice LLC +abc123,"Nice Corp, LLC" +9876,"Watson Group, LLC. " \ No newline at end of file