Next-generation Java: function-based coding style & mdash; function structures and advantages shared by Groovy, Scala, and Clojure, scalaclojure

Source: Internet
Author: User

Next-generation Java: Functional encoding style-functions shared by Groovy, Scala, and Clojure and scalaclojure

Original article address

Content
  • Imperative Processing
  • Function Processing
  • Advantages of functional programming

All next-generation Java languages include functional programming structures, allowing you to think about problems from a higher abstraction level. However, the differences in terms between languages make it difficult to see similar structures. This article will show the representation of common functional programming structures in the next-generation Java language, pointing out some nuances of those functions in implementation details.

When garbage collection becomes the mainstream, it eliminates all types of debugging problems and enables developers to manage complex and error-prone processes at runtime. Function programming is designed to achieve the same optimization for your algorithms, so that you can work at a higher abstraction level and perform complex optimization at runtime.

The next-generation Java language does not all occupy the same position from the imperative language to the functional language spectrum, but they all show function functions and idioms. Functional programming technology is clearly defined, but languages sometimes use different terms for the same functional concept, making it difficult to see similarities. In this article, I have compared the functional encoding styles of Scala, Groovy, and Clojure and discussed their advantages.

Imperative Processing

First, we will discuss a common problem and its imperative solution.

If a name list is given, some of them have only one character. The names in the list must be returned using commas (,) as delimiters. The strings do not contain single-letter names, and each name is capitalized. The Java code for implementing this algorithm is shown in Listing 1.

Listing 1. Imperative Processing

public class TheCompanyProcess {
    public String cleanNames(List<String> listOfNames) {
        StringBuilder result = new StringBuilder();
        for(int i = 0; i < listOfNames.size(); i++) {
            if (listOfNames.get(i).length() > 1) {
                result.append(capitalizeString(listOfNames.get(i))).append(",");
            }
        }
        return result.substring(0, result.length() - 1).toString();
    }
 
    public String capitalizeString(String s) {
        return s.substring(0, 1).toUpperCase() + s.substring(1, s.length());
    }
}

Since the entire list must be processed, the simplest way to solve the problem in Listing 1 is to useImperative Loop. For each name, check to see if the length is greater than 1. If the length is greater than 1, append the name of the first letterresultString, followed by a comma. The last name in the final string should not contain a comma, so I will remove it from the final return value.

In imperative programming, we recommend that you do not perform operations at a low level. In listing 1cleanNames()Method, three tasks are executed:FilterList to remove single characters, the first letter of each name in the listTransformIn uppercase, and then the listConversionIs a string. In imperative languages, I have to use the same low-level mechanism for all three tasks (iterate over the list ). Functional Languages treat filtering, transformation, and conversion as common operationsTherefore, they provide you with solutions to problems from different perspectives.

Function Processing

Functional programming languages and imperative languages have different problem classifications. Filter, transform, and convert logical categoriesFunction.These functions implement low-level transformations and rely on developers to compile the functions passed as parameters to customize the behavior of the functions. I can use pseudocode to generalize the problem in Listing 1:

listOfEmps -> filter(x.length > 1) -> transform(x.capitalize) -> 
   convert(x, y -> x + "," + y)

With functional languages, you can model this conceptual solution without worrying about implementation details.

  

This is very common in. NET-The chain syntax. In. NET, there are many function delegation, such as Action and Func. Function delegation can use Lambda expressions.

Scala implementation

Listing 2 uses Scala to implement the processing example in Listing 1. It looks like the previous pseudo code, including the necessary implementation details.

Listing 2. Scala Processing

val employees = List("neal", "s", "stu", "j", "rich", "bob")
val result = employees
  .filter(_.length() > 1)
  .map(_.capitalize)
  .reduce(_ + "," + _)

For a given name list, filter all names whose names are not greater than 1. Then, provide the output of the operationmap()Function, which executes the provided code block for each element of the set and returns the transformed set. Finally, frommap()Output set flow directionreduce()Function, which combines each element based on the rules provided in the Code block. In this example, I combine each pair of elements and use the inserted commas to connect them.

I don't have to consider what the parameter names are in the three function calls, so I can use a convenient Scala shortcut, that is, using_Skip the name.reduce()Functions start with the first two elements and combine them into one element to become the first element in the next concatenation. While browsing the list,reduce()Creates a comma-separated string.

I first demonstrate Scala implementation because I am familiar with its syntax andScala uses industry-specific names for filtering, transformation, and conversion concepts, namely filter, map, and reduce.

Groovy implementation

Groovy has the same functions, but the naming method is more consistent with that of scripting languages (such as Ruby. The Groovy version of the processing example in Listing 1 is shown in listing 3.

Listing 3. Groovy Processing

class TheCompanyProcess {
  public static String cleanUpNames(List listOfNames) {
    listOfNames
        .findAll {it.length() > 1}
        .collect {it.capitalize()}
        .join(',')
  }
}

Although listing 3 is structured like the Scala example in Listing 2, the method names are different. GroovyfindAllThe code block provided by the collection method application. The reserved code block istrue. Like Scala, Groovy includes an implicit parameter mechanism that uses predefineditImplicit parameters.collectMethod (GroovymapVersion) executes the provided code block for each element of the set. Groovy provides a function (join()), Concatenate the string set into a single string using the provided separator, which is exactly what is needed in this example.

Clojure implementation

Clojure is an applicationreduce,mapAndfilterFunction language, as shown in Listing 4.

Listing 4. Clojure processing example

(defn process [list-of-emps]
  (reduce str (interpose "," 
 
      (map clojure.string/capitalize 
        (filter #(< 1 (count %)) list-of-emps)))))

If you are not familiar with Clojure, you can use the code in Listing 4. Its structure may not be clear enough. Lisp such as Clojure is "from the inside out", so it must start from the final parameter valuelist-of-empsStart. Clojure's(filter )The function accepts two parameters: the function used for filtering (in this example, the anonymous function) and the set to be filtered. You can write a formal function definition for the first parameter, such(fn [x] (< 1 (count x)))But you can use Clojure to write anonymous functions more concisely. As in the preceding example, the result of the filter operation is a small set.(map )The function accepts the transform function as the first parameter and sets(filter )Operation Return Value) as the second parameter. Clojure's(map )The first parameter of a function is usually a function provided by the developer, but any function that accepts a single parameter is valid; built-incapitalizeThe function also meets the requirements. Finally,(map )The operation result becomes(reduce ).(reduce )The first parameter of is a composite function (applied(interpose )Returns(str )).(interpose )Insert the first parameter between each element of the Set (except the last one.

When there are too many nested functions, even the most experienced developers will feel a headache, such as in Listing 4(process )Function. Fortunately, the Macros in Clojure allow you to "adjust" the structure to a more readable order. The functions in listing 5 are the same as those in Listing 4.

Listing 5. Using Clojure's thread-last macro

(defn process2 [list-of-emps]
  (->> list-of-emps
       (filter #(< 1 (count %)))
       (map clojure.string/capitalize)
       (interpose ",")
       (reduce str)))
Advantages of functional programming

In a famous article titled "Beating the Averages", Paul Graham definedBlub Paradox: He "fabricated" a false language named Blub and considered Functional Comparison between other languages and Blub:

As long as our hypothetical Blub programmer looks down on a series of functions, he knows that he is looking down. Languages that are not as powerful as Blub are obviously not very powerful, because they lack some features that programmers are used. But when our hypothetical Blub programmer looked in another direction, that is, looking up a series of functions, he didn't realize that he was looking up. What he sees is just a weird language. He may think that they are almost the same in terms of functionality as Blub, but there are more things that are hard to understand. Blub is good enough for him because he can think about problems in the Blub environment.

For many Java developers, the code in Listing 2 looks strange and strange, so it is difficult to regard it as a good code. However, when you stop over-refining the details of task execution, it releases the more intelligent language and runtime potential, thus making powerful improvements. For example, the arrival of JVM (removing developers' memory management troubles) opens up a new R & D field for the creation of advanced garbage collection. When using imperative encoding, you are deeply immersed in the details of iterative loops, making it difficult to optimize concurrency. At a higher level, operations (such as filter, map, and reduce) can separate concepts and implementations, changes such as parallelism from a complex and detailed task to a simple API change.

Think about how to change the code in Listing 1 to multi-threaded code. Because you are closely involvedforThe details that occur during the loop, so you must also handle annoying concurrent code. Next, let's take a look at the Scala parallel version shown in Listing 6.

Listing 6. Implementing Process Parallelism

val parallelResult = employees
  .par
  .filter(f => f.length() > 1)
  .map(f => f.capitalize)
  .reduce(_ + "," + _)

The only difference between Listing 2 and Listing 6 is that.parMethod is added to the command stream..parMethod returns the parallel version of the Set Based on which subsequent operations are performed. Since I have set the operation as a high-level concept, more work can be done freely at the underlying runtime.

For imperative objects, developers often consider using reusable classes because their language encourages classes as building blocks. Function programming languages tend to reuse functions. Functional Languages construct complex general functions (suchfilter(),map()Andreduce()) And can be customized by functions provided as parameters. In functional languages, it is common to convert data structures to standard sets such as list and ing, because they can then be manipulated by powerful built-in functions. For example, there are many XML processing frameworks in the Java environment. Each Framework encapsulates its own private version of XML structure and delivers it through its own method. In languages such as Clojure, XML is converted to a ing-based standard data structure, which is open to powerful transformations, conciseness, and filtering operations that already exist in languages.

Conclusion

All modern languages contain or add functional programming structures, making functional programming an indispensable part of future development. The next-generation Java language implements powerful functional functions and sometimes uses different names and behaviors. This article introduces a new coding style in Scala, Groovy, and Clojure and demonstrates some advantages.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.