Java 8 has finally arrived! After years of waiting, Java programmers are finally able to get functional programming support in Java. The support of functional programming enables the flow of existing code and provides a powerful capability for Java. The most notable of these new features is the way Java programmers operate the database. Functional programming brings an exciting, simple and efficient database API. Java 8 will support accessible like C # A new way of accessing the database, such as LINQ and other language competitions.
functional way to work with data
Java 8 Not only adds functional support, it also extends the collection (Collection) class by using new functions to process data. Typically, Java processes large amounts of data with a large number of loops and iterators.
For example, suppose you have a collection that stores customer objects:
Collection<customer> customers;
If you are interested only in customers from Belgium, you will have to iterate over all of the customer objects and save only what you need.
collection<customer> Belgians = new arraylist<> ();
for (Customer c:customers) {
if (C.getcountry (). Equals ("Belgium"))
Belgians.add (c);
}
Not only does this cost 5 lines of code, but it's also not very abstract. What if you had 10 million objects? Would you speed up by filtering all objects with two threads? Then you will have to use a lot of dangerous multithreaded code to rewrite all the code.
With Java 8, only one line of code is required to achieve the same functionality. With support for functional programming, Java 8 allows you to write a function that shows you are interested in which customers (objects) and then uses that function to filter the collection. The new steams API for Java 8 supports you in doing this:
Customers.stream (). Filter (
C-> c.getcountry (). Equals ("Belgium")
);
The above Java 8 version of the code is not only shorter, but also easier to understand. It has few clichés (loops or iterators, etc.). The Code calls the filter () method, which is clearly the code used to filter the client (object) . You don't have to waste time reading the code in the loop to understand what it does with its data.
What if you want to execute this code concurrently? You just use another type of stream
Customers.parallelstream (). Filter (
C-> c.getcountry (). Equals ("Belgium")
);
What's even more exciting is that this functional style of code also applies to the database.
Using functional methods on the database
Traditionally, programmers need to use special database query statements to access database data. For example, the following is the use of JDBC code to find customers from Belgium:
PreparedStatement s = con.preparestatement (
"SELECT *"
+ "from Customer C"
+ "WHERE c.country =?");
S.setstring (1, "Belgium");
ResultSet rs = S.executequery ();
Most of the code is string, which causes the compiler to not discover errors and this sloppy code can cause security problems. There are also a lot of boilerplate code that makes writing data access code very redundant. Some tools, such as JOOQ, provide database query language by using a special Java library to resolve error checking and security issues. Or use object-relational mapping tools to save a lot of uninteresting code, but they can only be used in universal access queries, if complex queries are required, or a special database query language.
Using Java 8, you can query the database in a functional way with the help of a streaming API. For example, Jinq is an open source project that explores how future database APIs can make functional programming possible. Here is a database query using JINQ:
Customers.where (
C-> c.getcountry (). Equals ("Belgium")
);
This code is almost the same as the code that uses the streaming API. In fact, the future JINQ version allows you to write database queries directly using streaming APIs. When the code is running, JINQ will automatically translate it into a database query code, just as the JDBC query did before.
In this way, you can write efficient database queries even if you haven't learned some new database query languages. You can use the same style of code on the Java collection. You don't need a special Java compiler or virtual machine either. All the code compiles and runs on the normal Java 8 jdk. If your code has errors, the compiler will find them and report them to you, just like normal Java code.
JINQ support for complex queries like SQL92. Selection (selection), projection (projection), joins (connection), and subquery it all support. The algorithm of translating Java code into database query is very flexible and can be translated as long as it is acceptable. For example, JINQ can translate the following database queries, although it is complex.
Customers
. where (c-> c.getcountry (). Equals ("Belgium"))
. where (c-> {
if (c.getsalary () < 100000 ) return
c.getsalary () < C.getdebt ();
else return
c.getsalary () < 2 * C.GETDEBT ();
});
As you can see, Java 8 's functional programming is ideal for database queries. And the query is compact, even complex query can be competent.
Internal operation
But how does this work? How can a normal Java compiler convert Java code to a database query? What's so special about Java 8 that makes this possible?
The key to a new database pi that supports these functional styles is a bytecode analysis called symbolic execution. While your code is compiled by an ordinary Java compiler and runs in a normal Java virtual machine, JINQ can analyze and build database queries when you are compiled Java code. When using the Java 8 Streams API, it is often found that symbolic execution works best when analyzing short functions.
To understand how this symbolic execution works, the simplest way is to use an example. Let's examine how the following query was converted to the SQL query language by JINQ:
Customers
. where (c-> c.getcountry (). Equals ("Belgium"))
Initially, the variable customers is a collection whose corresponding database query is:
SELECT * from
Customers C
Then the WHERE () method is invoked, and a function is passed to it. In the Where () method, Jinq opens the. class file for this function, and gets the byte code that the function is compiled into to parse. In this example, instead of using the real bytecode, let's use some simple instructions to represent the bytecode of this function:
D = c.getcountry ()
e = "Belgium"
e = D.equals (e) return
E
Here, we assume that the function has been compiled into these four instructions by the Java compiler. This is what JINQ sees when you call the Where () method. How do you make jinq understand the code?
JINQ is analyzed by executing code. But Jinq does not run the code directly. It is "abstract" to run code: instead of using real variables and real values, JINQ uses symbols to represent all the values when executing code. This is why this analysis is known as "symbolic execution".
JINQ executes each instruction and tracks all side effects or everything that the code changes in the program state. Here is a chart showing all the side effects found when jinq executed these four lines of code in a symbolic way.
Examples of symbolic executions
In the diagram, you can see that after the first instruction was run, Jinq found two side effects: The variable D has changed and the method Customer.getcountry () is invoked. Because it is a symbolic execution, variable d does not give a real value, such as "USA" or "Denmark", which is assigned the symbolic value of c.getcountry ().
After all these instructions were symbolically executed, jinq the side effects. Since the variables D and e are local variables, any changes they make will be discarded after the function exits, so these side effects can be negligible. Jinq also knows that the Customer.getcountry () and String.Equals () methods do not modify any variables or display any output, so these method calls can also be ignored. Thus, JINQ can conclude that executing this function will only produce a function, and it will return C.getcountry (). Equals ("Belgium").
Once Jinq has understood the function passed to it in the Where () method, it can mix the knowledge of the database query and take precedence over the Customers collection to create a new database query.
Build database Query
This is how JINQ generates database queries from your code. The use of symbolic execution means that this approach is quite powerful for different code patterns that are output by different Java compilers. If Jinq encounters code that has side effects that cannot be translated into database queries, JINQ will keep your code unchanged. Because everything is written in normal Java code, JINQ can run those codes directly, and your code will produce the expected results.
This simple translation example should let you know how to query translation works. You can be sure that these algorithms can correctly generate database queries from your code.
Good Prospects
I hope I've let you taste the new ways Java 8 brings to database work in Java. Java 8-supported functional programming allows you to write code for a database in the same way that you write code for a Java collection. It is hoped that the existing database APIs will soon be extended to support these types of queries.