Personal blog written from scratch using Node.js, Bootstrap, and MySQL. https://jrtechs.net
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
6.5 KiB

  1. It's time I tell you all my un-popular opinion: Java is a fun language.
  2. Many people regard Java as a dingy old language with vanilla syntax.
  3. Please don't fret; I am here to share the forbidden knowledge and lure you into the rabbit hole that is functional programming esque syntax in Java. And yes, this goes way beyond merely having lambda statements.
  4. ![java meme](media/java.png)
  5. # Ways to create a list
  6. The plain old way of making a list would look something like this:
  7. ```java
  8. List<Integer> myList = new ArrayList<Integer>();
  9. myList.add(1);
  10. myList.add(2);
  11. myList.add(3);
  12. ```
  13. Using double brace syntax, you can simplify initialization.
  14. Everything within the double brace gets executed right after the constructor is called.
  15. Java does this by creating an anonymous inner class.
  16. From within this anonymous inner class, you can access any methods private to that class; additionally, since you are still within the scope of the object you are writing the code in, you have access to those methods as well.
  17. Double braces are a slick way to initialize objects, but many people won't recognize it because it is more obscure.
  18. ```java
  19. new ArrayList<Integer>()
  20. {{
  21. add(1); add(2); add(3);
  22. }};
  23. ```
  24. Using the streams class, you can create a sequence of objects, and then do a collection on that stream.
  25. ```java
  26. Stream.of(1,2,3).collect(Collectors.toList());
  27. ```
  28. Similar to the prior method, we can create an Instream instead.
  29. Note: calling the boxed() method on an Instream will turn it into a Stream<Integer>.
  30. ```java
  31. IntStream.range(1, 4).boxed().collect(Collectors.toList())
  32. ```
  33. If you are hip to all the new methods in java 1.9 and beyond, you can use the List.of() method. However, I avoid this method because Java 1.8 is still the defacto for compatibility at the moment.
  34. ```java
  35. List.of(1,2,3)
  36. ```
  37. # Map
  38. For the next few examples, we will be trying to access the integer values in a map object.
  39. ```java
  40. Map<String, Integer> datas = new HashMap<String, Integer>()
  41. {{
  42. put("one", 1);
  43. put("two", 2);
  44. put("three", 3);
  45. }};
  46. ```
  47. We will recreate"Map.values()-- a function that returns all the values in the map as a list.
  48. When we call stream on a map in Java, it will create a stream for the keys -- not the values.
  49. The map function is an essential concept in a functional language.
  50. In our example, we are using it to take each key, and then fetch the integer values mapped to it.
  51. The result of the map function is a Stream<Integer>, which we then aggregate in a list using the collect() function.
  52. ```java
  53. datas.keySet().stream().map(k -> datas.get(k))
  54. .collect(Collectors.toList());
  55. ```
  56. The prior lambda can get simplified to "datas::get" since the value that we are streaming over is getting passed directly to the method getting called.
  57. ```java
  58. datas.keySet().stream().map(datas::get)
  59. .collect(Collectors.toList())
  60. ```
  61. Simply mapping to another value may not appear exciting, but it gives us extreme power when creating streams that process data. This example creates a new list where each value is the values in the prior list multiplied by 3.
  62. ```java
  63. datas.keySet().stream().map(k -> datas.get(k) * 3)
  64. .collect(Collectors.toList())
  65. ```
  66. # More about loops
  67. A basic list traversal in Java looks something like this.
  68. ```java
  69. List<String> list = new ArrayList<String>()
  70. {{
  71. add("Biz"); add("Bar"); add("Foo");
  72. }};
  73. for(String s: list)
  74. {
  75. System.out.println(s);
  76. }
  77. ```
  78. Using our functional forEach method, traversing a list becomes a single-liner.
  79. ```java
  80. list.forEach(s-> System.out.println(s));
  81. ```
  82. The above example can be simplified since the lambda expression parameters are getting passed right into the function getting called.
  83. ```java
  84. list.forEach(System.out::println);
  85. ```
  86. The Collection.forEach() method uses the iterator of the collection.
  87. Using the iterator of the collection will make the processing order well-defined.
  88. However, if you use the Collection.stream.forEach(), the order of the traversal is undefined. IE: traversal order is not guaranteed to be the same as the original list.
  89. The Collection.parallelStream() stream is particularly useful because it enables us the execute the stream using multiple threads.
  90. ```java
  91. list.parallelStream().forEach(System.out::println);
  92. ```
  93. # Filter
  94. Filters get used when you want to exclude specific entries from your data.
  95. An example could be that you want to filter out all elements in your list
  96. that contain null values before inserting them into a database.
  97. ```java
  98. list.stream() // stream contains Biz, Bar, Foo
  99. .filter(s -> s.contains("B")) // stream contains Biz, bar
  100. .collect(Collectors.toList()) // list with Biz, bar
  101. ```
  102. It is worth mentioning that other methods are available to a stream, such as count(), which will count the number of elements in the stream.
  103. ```java
  104. list.stream().filter(s -> s.contains("B"))
  105. .count()
  106. ```
  107. When calling .findFirst() on a stream it will return an optional-- refers to a Maybe in other functional languages like Haskell.
  108. An optional is essentially saying that it might contain something cleaner than returning null because it is easier to catch and do error handling.
  109. The Optional.orElse() function fetches the data inside the optional, but, returns a default value if none is present.
  110. ```java
  111. list.stream().filter(s -> s.contains("B"))
  112. .findFirst().orElse("Nothing found!")
  113. ```
  114. More optional examples:
  115. ```java
  116. Optional<String> opt = Optional.empty();
  117. System.out.println(opt.orElse("Not present!"));
  118. // don't do this will throw an exception
  119. System.out.println(opt.get());
  120. opt = Optional.of("Woza");
  121. System.out.println(opt.orElse("Not present!"));
  122. ```
  123. It is also possible to turn an array into a stream to do list esque processing on it.
  124. ```java
  125. int[] array = {1,2,3,4};
  126. System.out.println(
  127. Arrays.stream(array)
  128. .filter(v -> v > 2) // gets all values greater than 2
  129. .map(v -> v * 2) // mults the values by 2
  130. .boxed()// converts intstream to a Stream<Integer>
  131. .collect(Collectors.toList())
  132. );
  133. ```
  134. Recently I've been doing data processing in Java with my [Steams Graphs Project](https://github.com/jrtechs/SteamFriendsGraph), and this has given me an appreciation of stream-based processing. Using JanusGraph with Gremlin in Java gives you native access to all the stream operators.
  135. ```java
  136. private List<Game> getPlayerGamesFromGraph(String id)
  137. {
  138. return con.getTraversal().V()
  139. .hasLabel(SteamGraph.KEY_PLAYER)
  140. .has(Player.KEY_STEAM_ID, id)
  141. .outE()
  142. .inV()
  143. .hasLabel(Game.KEY_DB)
  144. .valueMap()
  145. .toStream()
  146. .map(Game::new)
  147. .collect(Collectors.toList());
  148. }
  149. ```