This code is basically perfect (save for that little bug found by RoToRa that little bug found by RoToRa):
- Map initialization in a static initializer block
- constructor is made inaccessible
- the code does what the documentation says
- clever short circuiting
- implementation using explicit stack
However, there are a few points which we can talk about:
The JavaDoc doesn't mention that the string must contain at least two characters. I would expect that the string
""
is indeed balanced. For me, a balanced string would be described by the following EBNF grammar:<Balanced> ::= '(' <Balanced> ')' | '{' <Balanced> '}' | '[' <Balanced> ']' | epsilon
that is, the empty string is allowed via this recursive definition. Instead, you've implemented a recognizer for the following grammar:
<Balanced> ::= '(' <InnerBalanced> ')' | '{' <InnerBalanced> '}' | '[' <InnerBalanced> ']' <InnerBalanced> ::= <Balanced> | epsilon
You forgot to test that
str != null
You could use the diamond operator to invoke inference on generic arguments:
Map<Character, Character> brackets = new HashMap<>()
Stack<Character> stack = new Stack<>()
A user of your function can't specify custom parens like
<...>
. It would be good to enable some possibility of customization, and default to(...)
otherwise.If you enable custom parens, then there may be some ambiguity – each opening paren would be associated with a set of possible closing parens. Note that given an O(1) membership test, this won't affect the algorithmic complexity of your code. Examples:
|...|
(norm operator/abs
from mathematics),|...>
(Bra-ket notation from quantum physics),<...>
(mean value/expected value from statistics).When checking whether a given string has balanced parens, this string will usually contain non-paren text as well. A function that returns true for
q{foo($bar{baz} .= do {my $x = '('; bless \$x})}
given the delimiters{...}
would be useful in real-world applications. Unfortunately, this disables your check that the string must be of even length.You only support single "characters" as delimiters. It would be more flexible to allow arbitrary strings. Note that Java's
Character
s aren't real Unicode characters, but effectively only 16-bit code units. To represent any Unicode code point, we need one or two Java characters (think: "int
is the newchar
"). Note further that this is only sufficient for single code points, whereas one logical character ("grapheme") may consist of multiple code points.
This code is basically perfect (save for that little bug found by RoToRa):
- Map initialization in a static initializer block
- constructor is made inaccessible
- the code does what the documentation says
- clever short circuiting
- implementation using explicit stack
However, there are a few points which we can talk about:
The JavaDoc doesn't mention that the string must contain at least two characters. I would expect that the string
""
is indeed balanced. For me, a balanced string would be described by the following EBNF grammar:<Balanced> ::= '(' <Balanced> ')' | '{' <Balanced> '}' | '[' <Balanced> ']' | epsilon
that is, the empty string is allowed via this recursive definition. Instead, you've implemented a recognizer for the following grammar:
<Balanced> ::= '(' <InnerBalanced> ')' | '{' <InnerBalanced> '}' | '[' <InnerBalanced> ']' <InnerBalanced> ::= <Balanced> | epsilon
You forgot to test that
str != null
You could use the diamond operator to invoke inference on generic arguments:
Map<Character, Character> brackets = new HashMap<>()
Stack<Character> stack = new Stack<>()
A user of your function can't specify custom parens like
<...>
. It would be good to enable some possibility of customization, and default to(...)
otherwise.If you enable custom parens, then there may be some ambiguity – each opening paren would be associated with a set of possible closing parens. Note that given an O(1) membership test, this won't affect the algorithmic complexity of your code. Examples:
|...|
(norm operator/abs
from mathematics),|...>
(Bra-ket notation from quantum physics),<...>
(mean value/expected value from statistics).When checking whether a given string has balanced parens, this string will usually contain non-paren text as well. A function that returns true for
q{foo($bar{baz} .= do {my $x = '('; bless \$x})}
given the delimiters{...}
would be useful in real-world applications. Unfortunately, this disables your check that the string must be of even length.You only support single "characters" as delimiters. It would be more flexible to allow arbitrary strings. Note that Java's
Character
s aren't real Unicode characters, but effectively only 16-bit code units. To represent any Unicode code point, we need one or two Java characters (think: "int
is the newchar
"). Note further that this is only sufficient for single code points, whereas one logical character ("grapheme") may consist of multiple code points.
This code is basically perfect (save for that little bug found by RoToRa):
- Map initialization in a static initializer block
- constructor is made inaccessible
- the code does what the documentation says
- clever short circuiting
- implementation using explicit stack
However, there are a few points which we can talk about:
The JavaDoc doesn't mention that the string must contain at least two characters. I would expect that the string
""
is indeed balanced. For me, a balanced string would be described by the following EBNF grammar:<Balanced> ::= '(' <Balanced> ')' | '{' <Balanced> '}' | '[' <Balanced> ']' | epsilon
that is, the empty string is allowed via this recursive definition. Instead, you've implemented a recognizer for the following grammar:
<Balanced> ::= '(' <InnerBalanced> ')' | '{' <InnerBalanced> '}' | '[' <InnerBalanced> ']' <InnerBalanced> ::= <Balanced> | epsilon
You forgot to test that
str != null
You could use the diamond operator to invoke inference on generic arguments:
Map<Character, Character> brackets = new HashMap<>()
Stack<Character> stack = new Stack<>()
A user of your function can't specify custom parens like
<...>
. It would be good to enable some possibility of customization, and default to(...)
otherwise.If you enable custom parens, then there may be some ambiguity – each opening paren would be associated with a set of possible closing parens. Note that given an O(1) membership test, this won't affect the algorithmic complexity of your code. Examples:
|...|
(norm operator/abs
from mathematics),|...>
(Bra-ket notation from quantum physics),<...>
(mean value/expected value from statistics).When checking whether a given string has balanced parens, this string will usually contain non-paren text as well. A function that returns true for
q{foo($bar{baz} .= do {my $x = '('; bless \$x})}
given the delimiters{...}
would be useful in real-world applications. Unfortunately, this disables your check that the string must be of even length.You only support single "characters" as delimiters. It would be more flexible to allow arbitrary strings. Note that Java's
Character
s aren't real Unicode characters, but effectively only 16-bit code units. To represent any Unicode code point, we need one or two Java characters (think: "int
is the newchar
"). Note further that this is only sufficient for single code points, whereas one logical character ("grapheme") may consist of multiple code points.
This code is basically perfect (save for that little bug found by RoToRa):
- Map initialization in a static initializer block
- constructor is made inaccessible
- the code does what the documentation says
- clever short circuiting
- implementation using explicit stack
However, there are a few points which we can talk about:
The JavaDoc doesn't mention that the string must contain at least two characters. I would expect that the string
""
is indeed balanced. For me, a balanced string would be described by the following EBNF grammar:<Balanced> ::= '(' <Balanced> ')' | '{' <Balanced> '}' | '[' <Balanced> ']' | epsilon
that is, the empty string is allowed via this recursive definition. Instead, you've implemented a recognizer for the following grammar:
<Balanced> ::= '(' <InnerBalanced> ')' | '{' <InnerBalanced> '}' | '[' <InnerBalanced> ']' <InnerBalanced> ::= <Balanced> | epsilon
You forgot to test that
str != null
You could use the diamond operator to invoke inference on generic arguments:
Map<Character, Character> brackets = new HashMap<>()
Stack<Character> stack = new Stack<>()
A user of your function can't specify custom parens like
<...>
. It would be good to enable some possibility of customization, and default to(...)
otherwise.If you enable custom parens, then there may be some ambiguity – each opening paren would be associated with a set of possible closing parens. Note that given an O(1) membership test, this won't affect the algorithmic complexity of your code. Examples:
|...|
(norm operator/abs
from mathematics),|...>
(Bra-ket notation from quantum physics),<...>
(mean value/expected value from statistics).When checking whether a given string has balanced parens, this string will usually contain non-paren text as well. A function that returns true for
q{foo($bar{baz} .= do {my $x = '('; bless \$x})}
given the delimiters{...}
would be useful in real-world applications. Unfortunately, this disables your check that the string must be of even length.You only support single "characters" as delimiters. It would be more flexible to allow arbitrary strings. Note that Java's
Character
s aren't real Unicode characters, but effectively only 16-bit code units. To represent any Unicode code point, we need one or two Java characters (think: "int
is the newchar
"). Note further that this is only sufficient for single code points, whereas one logical character ("grapheme") may consist of multiple code points.